Android 音视频开发(四):使用 MediaExtractor API 解析mp4 文件

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;
    }

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容