什么是android中的MediaCodec,MediaExtractor和MediaMuxer?

huangapple go评论76阅读模式
英文:

What is MediaCodec, MediaExtractor and MediaMuxer in android?

问题

以下是翻译好的内容:

在安卓中,"MediaCodec"、"MediaExtractor"和"MediaMuxer"是什么意思?虽然我不是专业的视频从业者,但我基本了解编码和解码的含义。我需要知道每个类的功能以及它们在哪些用例中使用。

我还想知道:

  • 如果我想从相机预览中提取帧并创建包含某些编辑(如速度)的视频文件,我应该使用哪些类,它们是如何协同工作的?

  • 如果我想创建一个类似于ExoPlayer(不需要所有功能,只是一个简单的Dash自适应流媒体播放器),我应该使用哪些类,它们是如何协同工作的?

希望您能回答。谢谢。

英文:

What does MediaCodec, MediaExtractor and MediaMuxer mean in android? I am not a video person but I do know what encoding and decoding means, at a basic level. I need to know what are the functions of each classes and at which use cases are they used. <br/>I would also like to know:<br/>
<ul>
<li><b>If I want to extract frames from a camera preview and create a video file along with some editing (like speed), which classes should I use and how does it work together?</b></li>

<li><b>If I want to create a Video Player like Exoplayer (not all the functions but a simple Dash adaptive streaming player) , which classes should I use and how does it work together?</b></li>
</ul>
<br/>
Hope you will answer. Thank You.

答案1

得分: 1

让我首先说,如果你不了解视频编解码的工作原理,就很难理解这些 API。我建议你研究一下编码器和解码器的工作原理。

我将为每个部分提供一个过度简化的解释。


MediaCodec

MediaCodec 类可用于访问低级媒体编解码器,即编码器/解码器组件。它是 Android 低级多媒体支持基础架构的一部分。

因此,MediaCodec 处理视频数据包/缓冲区的解码或编码,并负责与编解码器的交互。

下面是如何初始化 MediaCodec 的示例:

// 通过传递 MIME 类型创建 Mediacodec 实例。它将选择适合此 MIME 类型的最佳编解码器
MediaCodec mDecoder = MediaCodec.createDecoderByType(mimeType);
// 传递 MediaFormat 实例和输出/渲染 Surface
mDecoder.configure(format, surface, null, 0);
mDecoder.start();

然后你可以开始传递数据给 MediaCodec,就像这样:

ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
int index = mDecoder.dequeueInputBuffer(timeout);
// 检查缓冲区是否可用
if (index >= 0) {
    // 获取已出队的缓冲区
    ByteBuffer buffer = inputBuffers[index];
    // 获取样本数据大小,以确定我们是否应该继续排队更多的缓冲区或者标记流结束
    int sampleSize = mExtractor.readSampleData(buffer, 0);
    if (sampleSize < 0) {
        // 标记 EOS,例如当你到达视频结尾时会发生这种情况。
        mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
    } else {
        // 排队已出队的缓冲区,并传递解码器的样本时间
        mDecoder.queueInputBuffer(index, 0, sampleSize, mExtractor.getSampleTime(), 0);
        mExtractor.advance();
    }
}

然后你从输出缓冲区中出队并将其释放到你的 Surface 上:

BufferInfo frameInfo = new BufferInfo();
int index = mDecoder.dequeueOutputBuffer(frameInfo, timeout);

switch (index) {
    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
        break;
    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
        MediaFormat newFormat = mDecoder.getOutputFormat();
        break;
    case MediaCodec.INFO_TRY_AGAIN_LATER:
        break;
    default:
        break;
}

// 现在你可以将帧推送到 Surface 上
// 这是你可以通过让线程短暂休眠来控制播放速度的地方

if (index > 0) {
    mDecoder.releaseOutputBuffer(bufferIndex, true);
}

MediaExtractor

MediaExtractor 用于从数据源中提取分离的、通常编码的媒体数据。

文档的描述已经很清楚了。

请看下面,我已经添加了注释以便更好理解:

// 初始化提取器
MediaExtractor mExtract = new MediaExtractor();
mExtract.setDataSource(mSource);

// 选择/设置视频轨道(如果可用)
int trackIndex = selectVideoTrack(mExtract);
if (trackIndex < 0)
    throw new IOException("找不到轨道");
mExtract.selectTrack(trackIndex);

// 提取器现在已经可以使用了

// 获取轨道格式
mFormat = mExtractor.getTrackFormat(trackIndex);

// 获取缓冲区大小以检查缓冲区是否可用
// 这将由 MediaCodec 用于确定缓冲区是否可用
sampleSize = mExtractor.readSampleData(buffer, 0);

MediaMuxer

MediaMuxer 用于复用基本流。目前 MediaMuxer 支持将输出作为 MP4、Webm 和 3GP 文件。自 Android Nougat 开始,它还支持在 MP4 中复用 B 帧。

这也很直白。它用于创建视频/音频文件,例如将两个视频文件合并在一起。

英文:

Let me start of by saying that it is hard to understand this API`s if you don't understand how video encoding/decoding works. I would suggest doing research about how encoders/decoders work.

I will provide an oversimplified explanation of each.


MediaCodec:

>MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components. It is part of the Android low-level multimedia support infrastructure

So MediaCodec handles the decoding or encoding of the video packets/buffers and is responsible for the interaction with the codec.

Here is an example of how to Initialize MediaCodec:

// Create Mediacodec instance by passing a mime type. It will select the best codec for this mime type
MediaCodec mDecoder = MediaCodec.createDecoderByType(mimeType); 
// Pass an instance on MediaFormat and the output/rendering Surface
mDecoder.configure(format, surface, null, 0); 
mDecoder.start();

You would then start passing buffers to MediaCodec, like this:

ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
int index = mDecoder.dequeueInputBuffer(timeout);
// Check if buffers are available
if (index &gt;= 0) { 
    // Get dequeued buffer
    ByteBuffer buffer = inputBuffers[index]; 
    // Get sample data size to determine if we should keep queuing more buffers or signal end of stream
    int sampleSize = mExtractor.readSampleData(buffer, 0); 
    if (sampleSize &lt; 0) { 
        // Signal EOS, this happens when you reach the end if the video, for example.
        mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
    } else { 
        // Queue the dequeued buffer and pass the extractors sample time
        mDecoder.queueInputBuffer(index, 0, sampleSize, mExtractor.getSampleTime(), 0);
        mExtractor.advance(); 
    } 
}

You then dequeue the output buffer and release it to your surface:

BufferInfo frameInfo = new BufferInfo(); 
int index mDecoder.dequeueOutputBuffer(frameInfo, timeout);

switch (index) { 
    case
        MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 
    break; 
    case
        MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: 
        MediaFormat newFormat = mDecoder.getOutputFormat(); 
    break; 
    case
        MediaCodec.INFO_TRY_AGAIN_LATER: break; default: 
    break; 
}

// You can now push the frames to the surface
// This is where you can control the playback speed, you can do this by letting your thread sleep momentarily

if (index &gt; 0) {
    mDecoder.releaseOutputBuffer(bufferIndex, true);
}



MediaExtractor:

>MediaExtractor facilitates extraction of demuxed, typically encoded, media data from a data source.

The documentation description is self-explanatory.

Have a look below, I've added comments to make it more understandable:

// Initialize the extractor
MediaExtractor() mExtract = new MediaExtractor(); mExtract.setDataSource(mSource);

// Select/set the video track (if available)
int trackIndex = selectVideoTrack(mExtract);
if(trackIndex &lt; 0) 
    throw new IOException(&quot;Can&#39;t find track&quot;);
mExtract.selectTrack(trackIndex);

// The extractor is now ready to be used

// Get the track format
mFormat = mExtractor.getTrackFormat(trackIndex);

// Get buffer size to check if a buffer is available
// This will be used by MediaCodec to determine if buffers are available
sampleSize = mExtractor.readSampleData(buffer, 0);

MediaMuxer:

>MediaMuxer facilitates muxing elementary streams. Currently MediaMuxer supports MP4, Webm and 3GP file as the output. It also supports muxing B-frames in MP4 since Android Nougat.

This is self-explanatory once again. It's used to create a video/audio file. For example, merging two video files together.

huangapple
  • 本文由 发表于 2020年10月23日 00:57:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/64487008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定