zoukankan      html  css  js  c++  java
  • Android 音视频开发(五):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件

    一个音视频文件是由音频和视频组成的,我们可以通过MediaExtractor、MediaMuxer把音频或视频给单独抽取出来,抽取出来的音频和视频能单独播放; 

    一、MediaExtractor API介绍

    MediaExtractor的作用是把音频和视频的数据进行分离。

    主要API介绍:

    • setDataSource(String path):即可以设置本地文件又可以设置网络文件
    • getTrackCount():得到源文件通道数 
    • getTrackFormat(int index):获取指定(index)的通道格式
    • getSampleTime():返回当前的时间戳 
    • readSampleData(ByteBuffer byteBuf, int offset):把指定通道中的数据按偏移量读取到ByteBuffer中;
    • advance():读取下一帧数据
    • release(): 读取结束后释放资源

    使用示例:

     MediaExtractor extractor = new MediaExtractor();
     extractor.setDataSource(...);
     int numTracks = extractor.getTrackCount();
     for (int i = 0; i < numTracks; ++i) {
       MediaFormat format = extractor.getTrackFormat(i);
       String mime = format.getString(MediaFormat.KEY_MIME);
       if (weAreInterestedInThisTrack) {
         extractor.selectTrack(i);
       }
     }
     ByteBuffer inputBuffer = ByteBuffer.allocate(...)
     while (extractor.readSampleData(inputBuffer, ...) >= 0) {
       int trackIndex = extractor.getSampleTrackIndex();
       long presentationTimeUs = extractor.getSampleTime();
       ...
       extractor.advance();
     }
    
     extractor.release();
     extractor = null;

    二、MediaMuxer API介绍

    MediaMuxer的作用是生成音频或视频文件;还可以把音频与视频混合成一个音视频文件。

    相关API介绍:

    • MediaMuxer(String path, int format):path:输出文件的名称  format:输出文件的格式;当前只支持MP4格式;
    • addTrack(MediaFormat format):添加通道;我们更多的是使用MediaCodec.getOutpurForma()或Extractor.getTrackFormat(int index)来获取MediaFormat;也可以自己创建;
    • start():开始合成文件
    • writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo):把ByteBuffer中的数据写入到在构造器设置的文件中;
    • stop():停止合成文件
    • release():释放资源

    使用示例:

    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();

    三、使用情境 

    3.1 从MP4文件中提取视频并生成新的视频文件

    public class MainActivity extends AppCompatActivity {
    
        private static final String SDCARD_PATH = Environment.getExternalStorageDirectory().getPath();
    
        private MediaExtractor mMediaExtractor;
        private MediaMuxer mMediaMuxer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // 获取权限
            int checkWriteExternalPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
            int checkReadExternalPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);if (checkWriteExternalPermission != PackageManager.PERMISSION_GRANTED ||
                    checkReadExternalPermission != PackageManager.PERMISSION_GRANTED) {
    
                ActivityCompat.requestPermissions(this, new String[]{
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
            }
    
            setContentView(R.layout.activity_main);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        process();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    
        private boolean process() throws IOException {
            mMediaExtractor = new MediaExtractor();
            mMediaExtractor.setDataSource(SDCARD_PATH + "/ss.mp4");
    
            int mVideoTrackIndex = -1;
            int framerate = 0;
            for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
                MediaFormat format = mMediaExtractor.getTrackFormat(i);
                String mime = format.getString(MediaFormat.KEY_MIME);
                if (!mime.startsWith("video/")) {
                    continue;
                }
                framerate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
                mMediaExtractor.selectTrack(i);
                mMediaMuxer = new MediaMuxer(SDCARD_PATH + "/ouput.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                mVideoTrackIndex = mMediaMuxer.addTrack(format);
                mMediaMuxer.start();
            }
    
            if (mMediaMuxer == null) {
                return false;
            }
    
            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
            info.presentationTimeUs = 0;
            ByteBuffer buffer = ByteBuffer.allocate(500 * 1024);
            int sampleSize = 0;
            while ((sampleSize = mMediaExtractor.readSampleData(buffer, 0)) > 0) {
    
                info.offset = 0;
                info.size = sampleSize;
                info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;
                info.presentationTimeUs += 1000 * 1000 / framerate;
                mMediaMuxer.writeSampleData(mVideoTrackIndex, buffer, info);
                mMediaExtractor.advance();
            }
    
            mMediaExtractor.release();
    
            mMediaMuxer.stop();
            mMediaMuxer.release();
    
            return true;
        }
    }

     

  • 相关阅读:
    进阶篇:3.1.8)DFM塑胶-注射模具和设备
    PAT-甲级-1001-A+B Format
    腾讯-004-两个排序数组的中位数
    机器学习三 决策树
    腾讯-002-两数相加
    2018.3.15
    2018.3.14
    2018.3.13
    废代码合集
    边缘检测程序(matlab)
  • 原文地址:https://www.cnblogs.com/renhui/p/7474096.html
Copyright © 2011-2022 走看看