1919
2020public class VideoEncoder {
2121
22+ private final String TAG = VideoEncoder .class .getSimpleName ();
2223 private final VideoEncodeParam videoEncodeParam ;
2324 private final ExecutorService executor = Executors .newSingleThreadExecutor ();
2425 private MediaCodec mediaCodec ;
@@ -28,6 +29,8 @@ public class VideoEncoder {
2829 private int MAX_BITRATE_LENGTH = 1000000 ;
2930 private int beginBitRate = 0 ;
3031
32+ private boolean isSupportNV21 = false ;
33+
3134 private String firstSupportColorFormatCodecName = "" ; // OMX.qcom.video.encoder.avc 和 c2.android.avc.encoder 过滤,这两个h264编码性能好一些。如果都不支持COLOR_FormatYUV420Planar,就用默认的方式。
3235
3336 public VideoEncoder (VideoEncodeParam param ) {
@@ -38,6 +41,8 @@ public VideoEncoder(VideoEncodeParam param) {
3841
3942 private void initMediaCodec () {
4043 try {
44+ checkSupportedColorFormats ("video/avc" ); // H.264 编码器
45+
4146 if (!firstSupportColorFormatCodecName .isEmpty ()) {
4247 mediaCodec = MediaCodec .createByCodecName (firstSupportColorFormatCodecName );
4348 } else {
@@ -55,8 +60,13 @@ private void initMediaCodec() {
5560 mediaFormat .setInteger (MediaFormat .KEY_BIT_RATE , bitRate );
5661 //描述视频格式的帧速率(以帧/秒为单位)的键。帧率,一般在15至30之内,太小容易造成视频卡顿。
5762 mediaFormat .setInteger (MediaFormat .KEY_FRAME_RATE , videoEncodeParam .getFrameRate ());
58- //色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同
59- mediaFormat .setInteger (MediaFormat .KEY_COLOR_FORMAT , MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420Planar );
63+ if (isSupportNV21 ) {
64+ //色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同
65+ mediaFormat .setInteger (MediaFormat .KEY_COLOR_FORMAT , MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420SemiPlanar );
66+ } else {
67+ //色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同
68+ mediaFormat .setInteger (MediaFormat .KEY_COLOR_FORMAT , MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420Planar );
69+ }
6070 //关键帧间隔时间,单位是秒
6171 mediaFormat .setInteger (MediaFormat .KEY_I_FRAME_INTERVAL , videoEncodeParam .getiFrameInterval ());
6272 mediaFormat .setInteger (MediaFormat .KEY_BITRATE_MODE , MediaCodecInfo .EncoderCapabilities .BITRATE_MODE_VBR );
@@ -74,6 +84,44 @@ private void initMediaCodec() {
7484 }
7585 }
7686
87+ private void checkSupportedColorFormats (String mimeType ) {
88+ if (android .os .Build .VERSION .SDK_INT >= android .os .Build .VERSION_CODES .LOLLIPOP ) {
89+ MediaCodecList codecList = null ;
90+ codecList = new MediaCodecList (MediaCodecList .ALL_CODECS );
91+ MediaCodecInfo [] codecInfos = codecList .getCodecInfos ();
92+
93+ for (MediaCodecInfo codecInfo : codecInfos ) {
94+ if (!codecInfo .isEncoder ()) {
95+ continue ;
96+ }
97+
98+ String [] supportedTypes = codecInfo .getSupportedTypes ();
99+ for (String type : supportedTypes ) {
100+ if (type .equalsIgnoreCase (mimeType )) {
101+ MediaCodecInfo .CodecCapabilities capabilities = codecInfo .getCapabilitiesForType (type );
102+ int [] colorFormats = capabilities .colorFormats ;
103+
104+ for (int colorFormat : colorFormats ) {
105+ switch (colorFormat ) {
106+ case MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420Planar :
107+ Log .e (TAG , "Supported color format: COLOR_FormatYUV420Planar" );
108+ isSupportNV21 = false ;
109+ return ;
110+ case MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420SemiPlanar :
111+ Log .e (TAG , "Supported color format: COLOR_FormatYUV420SemiPlanar" );
112+ isSupportNV21 = true ;
113+ return ;
114+ default :
115+ Log .e (TAG , "Supported color format: " + colorFormat );
116+ break ;
117+ }
118+ }
119+ }
120+ }
121+ }
122+ }
123+ }
124+
77125 //描述平均位速率(以位/秒为单位)的键。 关联的值是一个整数
78126 @ TargetApi (Build .VERSION_CODES .KITKAT )
79127 public void setVideoBitRate (int bitRate ) {
@@ -91,7 +139,7 @@ public void setVideoBitRate(int bitRate) {
91139 mediaCodec .setParameters (params );
92140
93141 } catch (IllegalStateException e ) {
94- Log .e (" TAG" , "updateBitrate failed" , e );
142+ Log .e (TAG , "updateBitrate failed" , e );
95143 }
96144 }
97145
@@ -104,24 +152,30 @@ public int getVideoBitRate() {
104152 public void encoderH264 (byte [] data , boolean mirror ) {
105153 if (executor .isShutdown ()) return ;
106154 executor .submit (() -> {
107- byte [] rotateBytes ;
108- //视频顺时针旋转90度
109- if (mirror ) {
110- rotateBytes = nv21Rotate270 (data , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
155+ byte [] readyToProcessBytes ;
156+ if (isSupportNV21 ) {
157+ //将NV21编码成NV12
158+ byte [] bytes = NV21ToNV12 (data , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
159+ //视频顺时针旋转90度
160+ byte [] nv12 = rotateNV290 (bytes , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
161+
162+ if (mirror ) {
163+ verticalMirror (nv12 , videoEncodeParam .getHeight (), videoEncodeParam .getWidth ());
164+ }
165+ readyToProcessBytes = nv12 ;
111166 } else {
112- rotateBytes = nv21Rotate90 (data , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
167+ byte [] rotateBytes ;
168+ //视频顺时针旋转90度
169+ if (mirror ) {
170+ rotateBytes = nv21Rotate270 (data , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
171+ } else {
172+ rotateBytes = nv21Rotate90 (data , videoEncodeParam .getWidth (), videoEncodeParam .getHeight ());
173+ }
174+ //将NV21编码成I420
175+ byte [] i420 = toI420 (rotateBytes , videoEncodeParam .getHeight (), videoEncodeParam .getWidth ());
176+ readyToProcessBytes = i420 ;
113177 }
114- //将NV21编码成I420
115- byte [] i420 = toI420 (rotateBytes , videoEncodeParam .getHeight (), videoEncodeParam .getWidth ());
116-
117- // //将NV21编码成NV12
118- // byte[] bytes = NV21ToNV12(data, videoEncodeParam.getWidth(), videoEncodeParam.getHeight());
119- // //视频顺时针旋转90度
120- // byte[] nv12 = rotateNV290(bytes, videoEncodeParam.getWidth(), videoEncodeParam.getHeight());
121- //
122- // if (mirror) {
123- // verticalMirror(nv12, videoEncodeParam.getHeight(), videoEncodeParam.getWidth());
124- // }
178+
125179
126180 try {
127181 //拿到输入缓冲区,用于传送数据进行编码
@@ -134,9 +188,9 @@ public void encoderH264(byte[] data, boolean mirror) {
134188 ByteBuffer inputBuffer = inputBuffers [inputBufferIndex ];
135189 inputBuffer .clear ();
136190 //往输入缓冲区写入数据
137- inputBuffer .put (i420 );
191+ inputBuffer .put (readyToProcessBytes );
138192 //五个参数,第一个是输入缓冲区的索引,第二个数据是输入缓冲区起始索引,第三个是放入的数据大小,第四个是时间戳,保证递增就是
139- mediaCodec .queueInputBuffer (inputBufferIndex , 0 , i420 .length , System .nanoTime () / 1000 , 0 );
193+ mediaCodec .queueInputBuffer (inputBufferIndex , 0 , readyToProcessBytes .length , System .nanoTime () / 1000 , 0 );
140194 }
141195 MediaCodec .BufferInfo bufferInfo = new MediaCodec .BufferInfo ();
142196 //拿到输出缓冲区的索引
@@ -152,7 +206,7 @@ public void encoderH264(byte[] data, boolean mirror) {
152206
153207 if (bufferInfo .flags == MediaCodec .BUFFER_FLAG_KEY_FRAME ) {
154208 // I 帧的处理逻辑
155- // Log.e(" TAG" , "==========I帧==============="+seq);
209+ // Log.e(TAG, "==========I帧==============="+seq);
156210 ByteBuffer spsb = mediaCodec .getOutputFormat ().getByteBuffer ("csd-0" );
157211 byte [] sps = new byte [spsb .remaining ()];
158212 spsb .get (sps , 0 , sps .length );
@@ -170,7 +224,7 @@ public void encoderH264(byte[] data, boolean mirror) {
170224 }
171225 } else {
172226 //outData就是输出的h264数据
173- // Log.e(" TAG" , "==========P帧===============" + seq);
227+ // Log.e(TAG, "==========P帧===============" + seq);
174228 if (encoderListener != null ) {
175229 encoderListener .onVideoEncoded (outData , System .currentTimeMillis (), seq );
176230 seq ++;
@@ -356,7 +410,7 @@ private void checkSupportedColorFormats() {
356410 for (int colorFormat : colorFormats ) {
357411
358412 if (colorFormat == MediaCodecInfo .CodecCapabilities .COLOR_FormatYUV420Planar ) {
359- Log .d (" TAG" , "Video encoder: " + codecInfo .getName () + ", supported color format: " + colorFormat );
413+ Log .d (TAG , "Video encoder: " + codecInfo .getName () + ", supported color format: " + colorFormat );
360414 firstSupportColorFormatCodecName = codecInfo .getName ();
361415 return ;
362416 }
0 commit comments