Android 原生解封装 MediaExtractor

271 阅读1分钟

在音视频处理的时候,省不了的就是解封装的操作,下面介绍一下,如何使用 Android 系统 api MediaExtractor,实现音视频的解封装。

初始化

一般来说,这里直接传文件路径进去就可以了,但是有时候我们拿到的不是文件路径,那么可以转成 fd 后在传给 MediaExtractor。

public AVHWReader(String file, Context context) {
    mediaExtractor = new MediaExtractor();
    FileDescriptor fd = null;

    try {
        mediaExtractor.setDataSource(file);
    } catch (IOException e) {
        Log.e(TAG, e.getMessage());
    }
}

获取轨道

通过 MIME 我们能获取音频、视频的轨道信息。

public int getVideoTrackIndex() {
    return getTrackIndex("video/");
}
public int getAudioTrackIndex() {
    return getTrackIndex("audio/");
}
public MediaFormat getMediaFormat(int trackIndex) {
    return mediaExtractor.getTrackFormat(trackIndex);
}
public MediaFormat getVideoMediaFormat() {
    int trackIndex = getVideoTrackIndex();
    return mediaExtractor.getTrackFormat(trackIndex);
}

读数据

这里的 ByteBuffer 要足够大,不然会产生异常。如果要同时读音视频数据,建议使用两个 Extractor。

public AVPacket readPacket(int trackIndex) {
    mediaExtractor.selectTrack(trackIndex);
    //if size too small, will produce illegal argument error
    ByteBuffer inputBuffer = ByteBuffer.allocate(1024*1024);
    int sampleSize = -1;
    try {
        sampleSize = mediaExtractor.readSampleData(inputBuffer,0);
    }catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }

    if (sampleSize == -1) {
        return null;
    }
    AVPacket packet = new AVPacket();

    packet.buffer = inputBuffer;
    packet.dts = mediaExtractor.getSampleTime();
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    bufferInfo.offset = 0;
    bufferInfo.size = inputBuffer.limit();
    bufferInfo.flags = mediaExtractor.getSampleFlags();
    bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime();
    packet.bufferInfo = bufferInfo;

    mediaExtractor.advance();
    return packet;
}

关闭

释放资源

public void stopReading() {
    mediaExtractor.release();
}