英文:
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 类可用于访问低级媒体编解码器,即编码器/解码器组件。它是 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 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 支持将输出作为 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 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 >= 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 < 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 > 0) {
mDecoder.releaseOutputBuffer(bufferIndex, true);
}
>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 < 0)
throw new IOException("Can't find track");
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论