MediaExtractor的使用

分离mp4、flv,生成视频H264/mpeg和音频mp3或aac(无adts头)

下面是应用层mediaExtractor使用,分离一mp4文件,生成h264和aac,并添加adts头文件。


import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * mp4extractor 分离器
 * 分离mp4 成h264 和 aac
 * 分别生成h264和aac文件(无adts头)
 * 

* android的无法分离高profile的h264文件,这里分离的是Baseline(profile) *

* 合成的时候,MP4,flv,rtmp都不需要adts头 * 合成的时候:hls,rtp,ts需要adts头 * 所以这里分离出来的aac是没有adts头的,mediainfo读取到的音频信息是从moov中box中读取的 */ public class MP4VideoExtractor { private static final String TAG = "MP4VideoExtractor"; //test3.mp4 h264,aac public static void exactorMedia(String sdcard_path) { FileOutputStream videoOutputStream = null; FileOutputStream audioOutputStream = null; MediaExtractor mediaExtractor = new MediaExtractor(); try { //分离的视频文件 File videoFile = new File(sdcard_path, "output_video.h264"); //分离的音频文件 File audioFile = new File(sdcard_path, "output_audio.aac"); videoOutputStream = new FileOutputStream(videoFile); audioOutputStream = new FileOutputStream(audioFile); //输入文件,也可以是网络文件 //oxford.mp4 视频 h264/baseline 音频 aac/lc 44.1k 2 channel 128kb/s mediaExtractor.setDataSource(sdcard_path + "/oxford.mp4"); //test3.mp4 视频h264 high 音频aac // mediaExtractor.setDataSource(sdcard_path + "/test3.mp4"); //test2.mp4 视频mpeg4 音频MP3 // mediaExtractor.setDataSource(sdcard_path + "/test2.mp4"); //信道总数 int trackCount = mediaExtractor.getTrackCount(); Log.d(TAG, "trackCount:" + trackCount); int audioTrackIndex = -1; int videoTrackIndex = -1; for (int i = 0; i < trackCount; i++) { MediaFormat trackFormat = mediaExtractor.getTrackFormat(i); String mineType = trackFormat.getString(MediaFormat.KEY_MIME); //视频信道 if (mineType.startsWith("video/")) { videoTrackIndex = i; } //音频信道 if (mineType.startsWith("audio/")) { audioTrackIndex = i; } } ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024); //切换到视频信道 mediaExtractor.selectTrack(videoTrackIndex); while (true) { int readSampleCount = mediaExtractor.readSampleData(byteBuffer, 0); Log.d(TAG, "video:readSampleCount:" + readSampleCount); if (readSampleCount < 0) { break; } //保存视频信道信息 byte[] buffer = new byte[readSampleCount]; byteBuffer.get(buffer); videoOutputStream.write(buffer);//buffer 写入到 videooutputstream中 byteBuffer.clear(); mediaExtractor.advance(); } //切换到音频信道 mediaExtractor.selectTrack(audioTrackIndex); while (true) { int readSampleCount = mediaExtractor.readSampleData(byteBuffer, 0); Log.d(TAG, "audio:readSampleCount:" + readSampleCount); if (readSampleCount < 0) { break; } //保存音频信息 byte[] buffer = new byte[readSampleCount]; byteBuffer.get(buffer); /************************* 用来为aac添加adts头**************************/ byte[] aacaudiobuffer = new byte[readSampleCount + 7]; addADTStoPacket(aacaudiobuffer, readSampleCount + 7); System.arraycopy(buffer, 0, aacaudiobuffer, 7, readSampleCount); audioOutputStream.write(aacaudiobuffer); /***************************************close**************************/ // audioOutputStream.write(buffer); byteBuffer.clear(); mediaExtractor.advance(); } } catch (IOException e) { e.printStackTrace(); } finally { Log.d(TAG, "mediaExtractor.release!\n"); mediaExtractor.release(); mediaExtractor = null; try { videoOutputStream.close(); audioOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } /** 这里之前遇到一个坑,以为这个packetLen是adts头的长度,也就是7,仔细看了下代码,发现这个不是adts头的长度,而是一帧音频的长度 * @param packet 一帧数据(包含adts头长度) * @param packetLen 一帧数据(包含adts头)的长度 */ private static void addADTStoPacket(byte[] packet, int packetLen) { int profile = 2; // AAC LC int freqIdx = getFreqIdx(44100); 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; } }

你可能感兴趣的:(MediaExtractor的使用)