Android多媒体之使用MediaExtractor与MediaMuxer分离音视频

MediaExtractor与MediaMuxer工具可以完美的将视频中的音视频分开来,可以对视频进行再配音合成达到自己的需求:

1.准备工作:声明基础变量

private final static String ROOT_PATH = Environment.getExternalStorageDirectory()
            .getAbsolutePath()+"/Media";
    private final static String MEDIA_DIVIDE_PATH = ROOT_PATH+"/divide";
    private final static String MEDIA_DUBBING_PATH = ROOT_PATH+"/dubbing";
    private String currentTaskPath = null;

    public final static String AUDIO_MIME = "audio";
    public final static String VIDEO_MIME = "video";

    private String videoOutputPath;

    public MediaDivider(){
        initOutputPath();
    }

    private void initOutputPath(){
        File file = new File(ROOT_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        File divide = new File(MEDIA_DIVIDE_PATH);
        if (!divide.exists()) {
            divide.exists();
        }
        currentTaskPath = createCurrentTaskPath();
        File currentTask = new File(currentTaskPath);
        if (!currentTask.exists()) {
            currentTask.mkdirs();
        }
        File dubbingPath = new File(MEDIA_DUBBING_PATH);
        if (!dubbingPath.exists()) {
            dubbingPath.mkdirs();
        }
    }

    private String createCurrentTaskPath(){
        return MEDIA_DIVIDE_PATH+"/"+System.currentTimeMillis();
    }

2.开始分离音视频:

public void divideMedia(String sourceMediaPath,String divideMime){
        MediaExtractor mediaExtractor = new MediaExtractor();
        try {
            mediaExtractor.setDataSource(sourceMediaPath);
            int trackCount = mediaExtractor.getTrackCount();
            for (int i=0;i<trackCount;i++) {
                MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i);
                String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
                if (!mime.startsWith(divideMime)) {
                    continue;
                }
                int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
                Log.d(TAG,"maxInputSize:"+maxInputSize);
                ByteBuffer videoByteBuffer = ByteBuffer.allocate(maxInputSize);
                if (divideMime.equals(AUDIO_MIME)) {
                    Log.d(TAG,"divide audio media to file");
                    String audioName = currentTaskPath+"/"
                            +sourceMediaPath.substring(sourceMediaPath.lastIndexOf('/')+1,sourceMediaPath.lastIndexOf('.'))
                            +"_audio_out.mp4";
                    Log.d(TAG,"audioName:"+audioName);
                    MediaMuxer mediaMuxer = new MediaMuxer(audioName,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                    int audioTrack = mediaMuxer.addTrack(mediaFormat);
                    mediaMuxer.start();
                    divideToOutputAudio(mediaExtractor,mediaMuxer,videoByteBuffer,mediaFormat,audioTrack,i);
                    finish(mediaExtractor,mediaMuxer);
                    break;
                } else if (divideMime.equals(VIDEO_MIME)) {
                    Log.d(TAG,"divide video media to file");
                    String videoName = currentTaskPath+"/"
                            +sourceMediaPath.substring(sourceMediaPath.lastIndexOf('/')+1,sourceMediaPath.lastIndexOf('.'))
                            +"_video_out.mp4";
                    Log.d(TAG,"videoName:"+videoName);
                    MediaMuxer mediaMuxer = new MediaMuxer(videoName,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                    int videoTrack = mediaMuxer.addTrack(mediaFormat);
                    mediaMuxer.start();
                    divideToOutputVideo(mediaExtractor,mediaMuxer,videoByteBuffer,mediaFormat,videoTrack,i);
                    finish(mediaExtractor,mediaMuxer);
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

该方法接受视频路径与所要分离出的媒体文件格式:audio或者video,根据媒体格式进行操作。

3.分离视频:

private void divideToOutputVideo(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer,ByteBuffer byteBuffer,MediaFormat format,
                                     int videoTrack,int videoTrackIndex) {
        long videoDuration = format.getLong(MediaFormat.KEY_DURATION);
        mediaExtractor.selectTrack(videoTrackIndex);
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        bufferInfo.presentationTimeUs = 0;
        long videoFrameTimes;
        mediaExtractor.readSampleData(byteBuffer,0);
        if (mediaExtractor.getSampleFlags()!=MediaExtractor.SAMPLE_FLAG_SYNC) {
            mediaExtractor.advance();
        }
        mediaExtractor.readSampleData(byteBuffer,0);
        mediaExtractor.advance();
        long firstFrame = mediaExtractor.getSampleTime();
        mediaExtractor.advance();
        mediaExtractor.readSampleData(byteBuffer,0);
        long secondFrame = mediaExtractor.getSampleTime();
        videoFrameTimes = Math.abs(secondFrame-firstFrame);
        mediaExtractor.seekTo(0,MediaExtractor.SEEK_TO_CLOSEST_SYNC);
        int sampleSize;
        while ((sampleSize=mediaExtractor.readSampleData(byteBuffer,0))!=-1){
            long presentTime = bufferInfo.presentationTimeUs;
            if (presentTime>=videoDuration) {
                mediaExtractor.unselectTrack(videoTrackIndex);
                break;
            }
            mediaExtractor.advance();
            bufferInfo.offset=0;
            bufferInfo.flags=mediaExtractor.getSampleFlags();
            bufferInfo.size=sampleSize;
            mediaMuxer.writeSampleData(videoTrack,byteBuffer,bufferInfo);
            bufferInfo.presentationTimeUs +=videoFrameTimes;
        }
        mediaExtractor.unselectTrack(videoTrackIndex);
    }

4.分离出音频:

private void divideToOutputAudio(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer,ByteBuffer byteBuffer,MediaFormat format,
                                     int audioTrack,int audioTrackIndex){
        int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
        int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
        Log.d(TAG,"rate:"+sampleRate+",c:"+channelCount);
        long audioDuration = format.getLong(MediaFormat.KEY_DURATION);
        mediaExtractor.selectTrack(audioTrackIndex);//参数为多媒体文件MediaExtractor获取到的track count的索引,选择音频轨道
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        bufferInfo.presentationTimeUs = 0;
        long audioSampleSize;
        mediaExtractor.readSampleData(byteBuffer,0);
        if (mediaExtractor.getSampleTime()==0) {
            mediaExtractor.advance();
        }
        mediaExtractor.readSampleData(byteBuffer,0);
        long firstRateSample = mediaExtractor.getSampleTime();
        mediaExtractor.advance();
        mediaExtractor.readSampleData(byteBuffer,0);
        long secondRateSample = mediaExtractor.getSampleTime();
        audioSampleSize = Math.abs(secondRateSample-firstRateSample);
        mediaExtractor.seekTo(0,MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
        int sampleSize;
        while ((sampleSize=mediaExtractor.readSampleData(byteBuffer,0))!=-1) {
            int trackIndex = mediaExtractor.getSampleTrackIndex();
            long presentationTimeUs = bufferInfo.presentationTimeUs;
            Log.d(TAG,"trackIndex:"+trackIndex+",presentationTimeUs:"+presentationTimeUs);
            if (presentationTimeUs>=audioDuration){
                mediaExtractor.unselectTrack(audioTrackIndex);
                break;
            }
            mediaExtractor.advance();
            bufferInfo.offset=0;
            bufferInfo.size=sampleSize;
            mediaMuxer.writeSampleData(audioTrack,byteBuffer,bufferInfo);//audioTrack为通过mediaMuxer.add()获取到的
            bufferInfo.presentationTimeUs += audioSampleSize;
        }
        mediaExtractor.unselectTrack(audioTrackIndex);
    }

5.释放资源:

    private void finish(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer){
        mediaMuxer.stop();
        mediaMuxer.release();
        mediaMuxer = null;
        mediaExtractor.release();
        mediaExtractor = null;
    }

转载于:https://my.oschina.net/fangfeiAI/blog/1544270

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值