一、MediaCodec
? MediaCodec类可用于访问低级媒体编解码器,即编码器/解码器组件。它是Android低级多媒体支持基础设施的一部分(通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface,以及AudioTrack.)。
1.1数据类型
编解码器处理三种数据:压缩数据、原始音频数据和原始视频数据。? 所有这三种数据都可以使用ByteBuffers,但您应该使用Surface用于原始视频数据以提高编解码器性能。Surface使用原生视频缓冲区,而不将其映射或复制到ByteBuffers因此,它的效率更高。
使用Surface时,通常无法访问原始视频数据,但可以使用ImageReader类来访问不安全的解码(原始)视频帧。这可能仍然比使用字节缓冲区更有效,因为一些本机缓冲区可以映射到直接的字节缓冲区。使用ByteBuffer模式时,可以使用Image类别和getInput/OutputImage(int)访问原始视频帧。
(1)压缩缓冲区
压缩数据可以作为解码器的输入、编码器的输出,需要指定数据的格式,这样codec才知道如何处理这些压缩数据
MediaFormat.KEY_MIME格式类型。
对于视频类型,通常是一个单独的压缩视频帧。
对于音频数据,通常是一个单独的访问单元(一个编码的音频段通常包含由格式类型决定的几毫秒的音频),但是这个要求稍微宽松一些,因为一个buffer可能包含多个编码的音频访问单元。
在这两种情况下,buffer都不会在任意字节边界上开始或结束,而是在帧/访问单元边界上开始或结束,除非它们被BUFFER_FLAG_PARTIAL_FRAME标记。
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
(2)原始音频缓冲区
原始音频数据 — PCM音频数据帧,这是每个通道按通道顺序的一个样本。
(3)原始视频缓冲区
在ByteBuffer模式下,视频buffer根据它们的MediaFormat.KEY_COLOR_FORMAT进行布局。可以从getCodecInfo(). MediaCodecInfo.getCapabilitiesForType.CodecCapability.colorFormats获取支持的颜色格式。视频编解码器可以支持三种颜色格式:
native raw video format: CodecCapabilities.COLOR_FormatSurface,可以与输入/输出的Surface一起使用。
flexible YUV buffers 例如CodecCapabilities.COLOR_FormatYUV420Flexible, 可以使用getInput/OutputImage(int)与输入/输出Surface一起使用,也可以在ByteBuffer模式下使用。
other, specific formats: 通常只支持ByteBuffer模式。有些颜色格式是厂商特有的,其他定义在CodecCapabilities。对于等价于flexible格式的颜色格式,可以使用getInput/OutputImage(int)。
从Build.VERSION_CODES.LOLLIPOP_MR1.开始,所有视频编解码器都支持flexible的YUV 4:2:0 buffer。
1.2 MediaCodec API
(1)MediaCodec创建:
createDecoderByType/createEncoderByType:根据特定MIME类型(如"video/avc")创建codec。然而,这不能用于注入特征,并且可能创建不能处理特定期望媒体格式的编解码器。
createByCodecName:知道组件的确切名称(如OMX.google.mp3.decoder)的时候,根据组件名创建codec。使用MediaCodecList可以获取组件的名称。
(2)MediaCodec配置与启动:
configure:配置解码器或者编码器。
四个参数:
MediaFormat format:输入数据的格式(解码器)或输出数据的所需格式(编码器)。传null等同于传递MediaFormat.MediaFormat作为空的MediaFormat。
Surface surface:指定Surface,用于解码器输出的渲染。如果编解码器不生成原始视频输出(例如,不是视频解码器)和/或想配置解码器输出ByteBuffer,则传null。
MediaCrypto crypto:指定一个crypto对象,用于对媒体数据进行安全解密。对于非安全的编解码器,传null。
int flags:当组件是编码器时,flags指定为常量CONFIGURE_FLAG_ENCODE。
(3)buffer处理的接口:
MediaCodec可以处理具体的视频流,主要有这几个方法:
getInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组
getInputBuffer(index) : 获取InputBuffers数组index下标的ByteBuffer
queueInputBuffer:输入流入队列
dequeueInputBuffer:从输入流队列中取数据进行编码操作
getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组
getOutputBuffer(index) : 获取OutputBuffers数组index下标的ByteBuffer
dequeueOutputBuffer:从输出队列中取出编码操作之后的数据
releaseOutputBuffer:处理完成,释放ByteBuffer数据
(4)处理完之后的操作:
flush:清空的输入和输出端口。
stop:终止decode/encode会话
release:释放编解码器实例使用的资源。
二、MediaFormat 一些属性理解
MediaFormat的格式被指定为键/值对。keys是字符串。values可以是整数、长整型、浮点型、字符串或ByteBuffer。(要素元数据被指定为 字符串/布尔 对。)
2.1 所有音频/视频格式通用的键,所有未标记为可选的键都是强制性的:
2.2 视频格式有以下键:
2.3 音频格式有以下键:?
?
2.4 字幕格式有以下关键字:
线格式的类型。KEY_LANGUAGE线内容的语言。KEY_CAPTION_SERVICE_NUMBER(同Internationalorganizations)国际组织可选,隐藏字幕服务或频道号。
2.5 图像格式有以下键:?
三、Image
与媒体源一起使用的单个完整图像缓冲区,例如 MediaCodec或 CameraDevice 。
该类允许通过一个或多个ByteBuffers高效地直接应用程序访问图像的像素数据。 每个缓冲区都封装在描述该平面中像素数据布局的Image.Plane中。 由于这种直接访问方式,与Bitmap类不同,图像不能直接用作UI资源。
由于图像通常由硬件组件直接生成或使用,因此它们是整个系统共享的有限资源,应在不再需要时立即关闭。
例如,当使用ImageReader类从各种媒体源读出图像时,一旦达到the maximum outstanding image count ,不关闭旧的图像对象将阻止新图像的可用性。 发生这种情况时,获取新图像的函数通常会抛出IllegalStateException 。
3.1 getPlanes() 方法
获取该图像的像素平面阵列,平面的数量由图像的格式决定。这个需要了解ImageFormat的格式了,这个以后再了解。
3.2 ImageFormat.getBitsPerPixel()方法
使用此函数可检索ImageFormat的每个像素的位数。
这个在此就点一下算了,之后在单独开一节来具体讲解。
四、demo实现
//解码操作,返回YUV加载的bitmap图片
public class ImageShowActivity extends Activity {
private TextView tv_yun;
//图片的个数
private int imageNum = 0;
private final String mVideoPath = Environment.getExternalStorageDirectory() + "/Pictures/music.mp4";
private MediaExtractor extractor;//用于解封装
private MediaFormat videoFormat;//保存视频轨道的媒体格式
private MediaCodec mediaCodec;//解码视频轨道资源
private int rotation;
private long duration;
//用于代表YUV的种类
public static final int YUV420P = 0;
public static final int YUV420SP = 1;
public static final int NV21 = 2;
//保存YUV数据的byte[]
private byte[] bytes;
private static int width;
private static int height;
//1.创建MediaExtractor和MediaCodec : MediaExtractor负责解封装,MediaCodec负责解码视频轨道资源
//2.解码获取图片,并进行转换:YUV_420_888-->NV21
//3.YuvImage 加载nv21,转化成Bitmap用于显示。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_show);
tv_yun = findViewById(R.id.tv_image_yuv);
GetVideo();
}
}
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
|