提取编码后的样本

MediaExtractorCompat 类是平台 MediaExtractor 类的直接替代,可提供相同的 API 和功能。它有助于从数据源中提取解复用的媒体数据(通常是编码的)。

它会将容器文件(如 MP4 或 MKV)分离为各个轨道,例如视频、音频和字幕。然后,提取器会从这些轨道中读取原始的编码数据,作为一系列样本(例如,单个压缩视频帧或音频块),然后再将这些数据发送到解码器。

常见用例包括:

  • 转码重混:从轨道读取编码后的样本,以更改编解码器(转码)或将视频流重新打包到新容器中(重混),例如将 MP4 文件转换为 MKV。
  • 选择性内容提取:隔离并保存单个轨道,例如从视频文件中提取音频流。
  • 低级别调试:检查单个样本以调试文件损坏、时间戳问题或其他问题。
  • 构建自定义播放器:对于小众用例,构建可完全控制媒体流水线的自定义播放器。

概览

以下代码示例展示了如何使用 MediaExtractorCompat

Kotlin

fun extractSamples(context: Context, mediaPath: String) {
    val extractor = MediaExtractorCompat(context)
    try {
        // 1. Setup the extractor
        extractor.setDataSource(mediaPath)

        // Find and select available tracks
        for (i in 0 until extractor.trackCount) {
            val format = extractor.getTrackFormat(i)
            extractor.selectTrack(i)
        }

        // 2. Process samples
        val buffer = ByteBuffer.allocate(10 * 1024 * 1024)
        while (true) {
            // Read an encoded sample into the buffer.
            val bytesRead = extractor.readSampleData(buffer, 0)
            if (bytesRead < 0) break

            // Access sample metadata
            val trackIndex = extractor.sampleTrackIndex
            val presentationTimeUs = extractor.sampleTime
            val sampleSize = extractor.sampleSize

            extractor.advance()
        }
    } catch (e: IOException) {
        throw RuntimeException(e)
    } finally {
        // 3. Release the extractor
        extractor.release()
    }
}

Java

public void extractSamples(Context context, String mediaPath) {
    MediaExtractorCompat extractor = new MediaExtractorCompat(context);
    try {
        // 1. Setup the extractor
        extractor.setDataSource(mediaPath);

        // Find and select available tracks
        for (int i = 0; i < extractor.getTrackCount(); i++) {
            MediaFormat format = extractor.getTrackFormat(i);
            extractor.selectTrack(i);
        }

        // 2. Process samples
        ByteBuffer buffer = ByteBuffer.allocate(10 * 1024 * 1024);
        while (true) {
            // Read an encoded sample into the buffer.
            int bytesRead = extractor.readSampleData(buffer, 0);
            if (bytesRead < 0) break;

            // Access sample metadata
            int trackIndex = extractor.getSampleTrackIndex();
            long presentationTimeUs = extractor.getSampleTime();
            long sampleSize = extractor.getSampleSize();

            extractor.advance();
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        // 3. Release the extractor
        extractor.release();
    }
}