Android 音视频学习:MediaExtractor和MediaMuxer学习

概述

继续学习MediaExtractor和MediaMuxer,主要作用就是音视频的分离和合成,此篇博客仅作为笔记使用,以防之后忘记

MediaExtractor

这个类的主要作用是把音频数据和视频数据分离

主要的API

方法 描述
setDataSource(String path) 设置源文件,既可以是本地文件也可以是网络文件
getTrackCount() 获取源文件的通道数
getTrackFormat(int index) 获取指定index的通道格式
getSampleTime() 以微秒为单位返回当前样本的呈现时间。
readSampleData(ByteBuffer byteBuf, int offset) 把指定通道中的数据,按照偏移量读取到ByteBuffer中
advance() 读取下一帧的数据
release() 完成后释放资源

MediaMuxer

这个类的组要作用是生成音频视频文件,还可以把音频和视频文件合成一个音视频文件

主要的API

方法 描述
MediaMuxer(String path, int format) path:输出文件的名称,format:输出文件的格式
addTrack(MediaFormat format) 添加通道,我们可以用MediaCodec.getOutpurForma()或者Extractor.getTrackFormat(int index)来获取MediaFormat,也可以自己建
start() 开始合成文件
writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) 把ByteBuffer的数据写入到文件中
stop() 停止合成
release() 释放资源

实战

MediaExtractor的使用

private void start() {
    
    
        FileOutputStream videooutputStream = null;
        FileOutputStream audiooutputStream = null;
        MediaExtractor mediaExtractor = null;
        try {
    
    
            File videofile = new File("/sdcard/aaapcm/video.mp4");
            File audiofile = new File("/sdcard/aaapcm/audio.pcm");
            videooutputStream = new FileOutputStream(videofile);
            audiooutputStream = new FileOutputStream(audiofile);
            mediaExtractor = new MediaExtractor();
            //设置源文件
            mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
            //获取通道数
            int trackCount = mediaExtractor.getTrackCount();
            int audio = -1;
            int video = -1;
            for (int i = 0; i < trackCount; i++) {
    
    
                MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
                String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
                Log.d("mmm", formatString);
                //视频通道
                if (formatString.startsWith("video/")) {
    
    
                    video = i;
                    Log.d("mmm", "视频" + video);
                }

                //音频通道
                if (formatString.startsWith("audio/")) {
    
    
                    audio = i;
                    Log.d("mmm", "音频" + audio);
                }
            }

            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);

            //选择视频通道
            mediaExtractor.selectTrack(video);
            int i;
            //拿到视频通道的数据,写入到文件
            while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                byte[] bytes = new byte[i];
                byteBuffer.get(bytes);
                videooutputStream.write(bytes);
                byteBuffer.clear();
                mediaExtractor.advance();
            }
            videooutputStream.close();

            
            //选择音频通道
            mediaExtractor.selectTrack(audio);
            //拿到音频通道的数据并写入文件
            while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                byte[] bytes = new byte[i];
                byteBuffer.get(bytes);
                audiooutputStream.write(bytes);
                byteBuffer.clear();
                mediaExtractor.advance();
            }
            audiooutputStream.close();

            Log.d("mmm", "分离结束");


        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            if (mediaExtractor != null) {
    
    
                mediaExtractor.release();
            }
        }
    }

这部分代码主要是分离源文件的音频和视频分别保存在俩个文件中,分离后的文件并不能播放,需要在次合成才行,下面继续看下分析可播放的音频和视频

MediaMuxer的使用

这个需要MediaMuxer和MediaExtractor配合使用

分离视频数据并合成到新的MP4文件,新的MP4可播放

    public void video() {
    
    
        MediaMuxer mediaMuxer = null;
        try {
    
    
            MediaExtractor mediaExtractor = new MediaExtractor();
            //设置源文件
            mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
            //获取通道数
            int trackCount = mediaExtractor.getTrackCount();
            int videoTrackindex = -1;
            int framerate = -1;
            for (int i = 0; i < trackCount; i++) {
    
    
                MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
                String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
                //找到视频通道
                if (formatString.startsWith("video/")) {
    
    
                    framerate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
                    //选择视频通道
                    mediaExtractor.selectTrack(i);
                    //创建MediaMuxer
                    mediaMuxer = new MediaMuxer("/sdcard/aaapcm/video11.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                    //添加通道
                    videoTrackindex = mediaMuxer.addTrack(trackFormat);
                    //开始合成
                    mediaMuxer.start();
                    break;
                }
            }

            if (mediaMuxer == null) {
    
    
                return;
            }

            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            bufferInfo.presentationTimeUs = 0;

            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);

            int i = 0;
            //从源文件读取视频数据
            while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                bufferInfo.offset = 0;
                bufferInfo.size = i;
                bufferInfo.flags = mediaExtractor.getSampleFlags();
                bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
                //把读取到的视频数据重新合成到新的文件
                mediaMuxer.writeSampleData(videoTrackindex, byteBuffer, bufferInfo);
                mediaExtractor.advance();
            }

            mediaExtractor.release();

            mediaMuxer.stop();
            mediaMuxer.release();

            Log.d("mmm", "分离视频结束");

        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

分离音频数据并合成到新的wav文件,新的wav可播放

  public void audio() {
    
    
        MediaMuxer mediaMuxer = null;
        try {
    
    
            MediaExtractor mediaExtractor = new MediaExtractor();
            //添加源文件
            mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
            //获取通道数
            int trackCount = mediaExtractor.getTrackCount();
            int audioTrackindex = -1;
            int framerate = -1;
            for (int i = 0; i < trackCount; i++) {
    
    
                MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
                String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
                //找到音频通道
                if (formatString.startsWith("audio/")) {
    
    
                    mediaExtractor.selectTrack(i);
                    //创建MediaMuxer
                    mediaMuxer = new MediaMuxer("/sdcard/aaapcm/video11.wav", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                    //添加通道
                    audioTrackindex = mediaMuxer.addTrack(trackFormat);
                    //开始合成
                    mediaMuxer.start();
                }

                if (formatString.startsWith("video/")) {
    
    
                    framerate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
                    break;
                }


            }

            if (mediaMuxer == null) {
    
    
                return;
            }

            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            bufferInfo.presentationTimeUs = 0;

            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);

            int i = 0;
            //分离音频数据
            while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                bufferInfo.offset = 0;
                bufferInfo.size = i;
                bufferInfo.flags = mediaExtractor.getSampleFlags();
                bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
                //把分离的音频数据合成到新的文件
                mediaMuxer.writeSampleData(audioTrackindex, byteBuffer, bufferInfo);
                mediaExtractor.advance();
            }

            mediaExtractor.release();

            mediaMuxer.stop();
            mediaMuxer.release();

            Log.d("mmm", "分离音频结束");

        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

把刚才分离出来的视频文件和音频文件重新合成为音视频文件

    public void hecheng() {
    
    
        try {
    
    
            MediaExtractor videoExtractor = new MediaExtractor();
            videoExtractor.setDataSource("/sdcard/aaapcm/video11.mp4");
            int trackCount = videoExtractor.getTrackCount();
            int framerate = 0;
            MediaFormat videotrackFormat = null;
            for (int i = 0; i < trackCount; i++) {
    
    
                videotrackFormat = videoExtractor.getTrackFormat(i);
                String formatString = videotrackFormat.getString(MediaFormat.KEY_MIME);
                if (formatString.startsWith("video/")) {
    
    
                    videoExtractor.selectTrack(i);
                    framerate = videotrackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
                }
            }

            MediaExtractor audioExtractor = new MediaExtractor();
            audioExtractor.setDataSource("/sdcard/aaapcm/video11.wav");
            MediaFormat audiotrackFormat = null;
            int trackCount1 = audioExtractor.getTrackCount();
            for (int i = 0; i < trackCount1; i++) {
    
    
                audiotrackFormat = audioExtractor.getTrackFormat(i);
                String formatString = audiotrackFormat.getString(MediaFormat.KEY_MIME);
                if (formatString.startsWith("audio/")) {
    
    
                    audioExtractor.selectTrack(i);
                }
            }

            MediaCodec.BufferInfo videobufferInfo = new MediaCodec.BufferInfo();
            MediaCodec.BufferInfo audiobufferInfo = new MediaCodec.BufferInfo();


            MediaMuxer mediaMuxer = new MediaMuxer("sdcard/aaapcm/hecheng.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            int writeAudioTrackIndex = mediaMuxer.addTrack(audiotrackFormat);
            int writeVideoTrackIndex = mediaMuxer.addTrack(videotrackFormat);
            mediaMuxer.start();

            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
            int i;
            while ((i = videoExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                videobufferInfo.size = i;
                videobufferInfo.offset = 0;
                videobufferInfo.flags = videoExtractor.getSampleFlags();
                videobufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
                mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videobufferInfo);
                videoExtractor.advance();
            }

            while ((i = audioExtractor.readSampleData(byteBuffer, 0)) > 0) {
    
    
                audiobufferInfo.size = i;
                audiobufferInfo.offset = 0;
                audiobufferInfo.flags = audioExtractor.getSampleFlags();
                audiobufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
                mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audiobufferInfo);
                audioExtractor.advance();
            }

            videoExtractor.release();
            audioExtractor.release();
            mediaMuxer.stop();
            mediaMuxer.release();

            Log.d("mmm", "合成完毕");


        } catch (IOException e) {
    
    
            e.printStackTrace();
        }

    }

参考

https://blog.csdn.net/zhi184816/article/details/52514138
https://www.cnblogs.com/renhui/p/7478527.html

猜你喜欢

转载自blog.csdn.net/qq_34760508/article/details/106660782