MediaExtractor&MediaMuxer解析和封装MP4文件

MediaExtractor API介绍

MediaExtractor主要用于多媒体文件的音视频数据的分离。
该类主要用于音视频混合数据的分离,接口比较简单,首先要通过setDataSource(String path)函数设置数据源,数据源可以是本地文件地址,也可以使用HTTP协议的网络码流地址。

然后,可以通过下面的代码块,来获取码流的详细信息,如:MimeType,分辨率、编码格式、码率、帧率等等。

主要API介绍:

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

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():释放资源

demo

Demo的目标:提取input.mp4文件中的视频数据,生成除去音频数据之后的纯视频output.mp4文件:

import android.app.Activity;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaMuxer.OutputFormat;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;

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

public class MainActivity extends Activity {

    private static final String SDCARD_PATH = Environment.getExternalStorageDirectory().getPath();
    private static final String INPUT_FILEPATH = SDCARD_PATH + "/input.mp4";
    private static final String OUTPUT_FILEPATH = SDCARD_PATH + "/output.mp4";

    private TextView mLogView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLogView = (TextView) findViewById(R.id.LogView);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    transcode(INPUT_FILEPATH, OUTPUT_FILEPATH);
                } catch (IOException e) {
                    e.printStackTrace();
                    logout(e.getMessage());
                }
            }
        }).start();
    }

    protected boolean transcode(String input, String output) throws IOException {

        logout("start processing...");

        MediaMuxer muxer = null;

        MediaExtractor extractor = new MediaExtractor();
        extractor.setDataSource(input);

        logout("start demuxer: " + input);

        int mVideoTrackIndex = -1;
        for (int i = 0; i < extractor.getTrackCount(); i++) {
            MediaFormat format = extractor.getTrackFormat(i);
            String mime = format.getString(MediaFormat.KEY_MIME);
            if (!mime.startsWith("video")) {
                logout("mime not video, continue search");
                continue;
            }
            extractor.selectTrack(i);
            muxer = new MediaMuxer(output, OutputFormat.MUXER_OUTPUT_MPEG_4);
            mVideoTrackIndex = muxer.addTrack(format);
            muxer.start();
            logout("start muxer: " + output);
        }

        if (muxer == null) {
            logout("no video found !");
            return false;
        }

        BufferInfo info = new BufferInfo();
        info.presentationTimeUs = 0;
        ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024 * 2);
        while (true) {
            int sampleSize = extractor.readSampleData(buffer, 0);
            if (sampleSize < 0) {
                logout("read sample data failed , break !");
                break;
            }
            info.offset = 0;
            info.size = sampleSize;
            info.flags = extractor.getSampleFlags();
            info.presentationTimeUs = extractor.getSampleTime();
            boolean keyframe = (info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) > 0;
            logout("write sample " + keyframe + ", " + sampleSize + ", " + info.presentationTimeUs);
            muxer.writeSampleData(mVideoTrackIndex, buffer, info);
            extractor.advance();
        }

        extractor.release();

        muxer.stop();
        muxer.release();

        logout("process success !");

        return true;
    }

    private void logout(final String content) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.i("MediaDemo", content);
                mLogView.setText(mLogView.getText() + "\n" + content);
            }
        });
    }
}

参考资料

Android 视频分离和合成(MediaMuxer和MediaExtractor)
https://blog.csdn.net/zhi184816/article/details/52514138

https://github.com/Jhuster/Android/tree/master/MediaDemo

Android 音视频开发(五):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件
http://www.cnblogs.com/renhui/p/7474096.html

Android中如何提取和生成mp4文件
http://blog.51cto.com/ticktick/1710743

你可能感兴趣的:(音视频)