From cf675a956d060e1ef978c63ba21128e615f016f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?whalensun=28=E5=AD=99=E4=BC=9F=29?= <532125505@qq.com> Date: Fri, 26 Aug 2022 19:05:44 +0800 Subject: [PATCH] =?UTF-8?q?master=E4=B8=8A=E4=BF=AE=E6=94=B9video-sdk?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=90=8C=E6=AD=A5=E5=88=B0v2.4.x=E4=B8=8A?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I09e7e62af6389b0506adb3d42b9b08fb244f5c1d --- sdk/video-link-android/build.gradle | 2 +- .../iot/video/link/encoder/AudioEncoder.java | 82 ++++++++++++++++++- .../iot/video/link/encoder/VideoEncoder.java | 37 ++++++++- 3 files changed, 115 insertions(+), 6 deletions(-) diff --git a/sdk/video-link-android/build.gradle b/sdk/video-link-android/build.gradle index 378a09f19..bf3d71bbc 100644 --- a/sdk/video-link-android/build.gradle +++ b/sdk/video-link-android/build.gradle @@ -49,7 +49,7 @@ dependencies { // changing = true // } // api 'com.tencent.iot.thirdparty.android:xp2p-sdk:2.4.23' - api 'com.tencent.iot.thirdparty.android:xp2p-sdk:2.4.28' + api 'com.tencent.iot.thirdparty.android:xp2p-sdk:2.4.30' api 'com.tencent.iot.thirdparty.android:media-server:1.0.2' } diff --git a/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/AudioEncoder.java b/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/AudioEncoder.java index 848b34753..80b55f90e 100644 --- a/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/AudioEncoder.java +++ b/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/AudioEncoder.java @@ -4,6 +4,8 @@ import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaFormat; +import android.media.audiofx.AcousticEchoCanceler; +import android.media.audiofx.AutomaticGainControl; import android.os.Build; import android.util.Log; @@ -44,6 +46,8 @@ public class AudioEncoder { private final String TAG = AudioEncoder.class.getSimpleName(); private MediaCodec audioCodec; private AudioRecord audioRecord; + private AcousticEchoCanceler canceler; + private AutomaticGainControl control; private final MicParam micParam; private final AudioEncodeParam audioEncodeParam; @@ -55,9 +59,21 @@ public class AudioEncoder { public AudioEncoder(MicParam micParam, AudioEncodeParam audioEncodeParam) { + this(micParam, audioEncodeParam, false, false); + } + + + public AudioEncoder(MicParam micParam, AudioEncodeParam audioEncodeParam, boolean enableAEC, boolean enableAGC) { this.micParam = micParam; this.audioEncodeParam = audioEncodeParam; initAudio(); + int audioSessionId = audioRecord.getAudioSessionId(); + if (enableAEC && audioSessionId != 0) { + Log.e(TAG, "=====initAEC result: " + initAEC(audioSessionId)); + } + if (enableAGC && audioSessionId != 0) { + Log.e(TAG, "=====initAGC result: " + initAGC(audioSessionId)); + } } public void setOnEncodeListener(OnEncodeListener listener) { @@ -82,7 +98,6 @@ private void initAudio() { } } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void start() { new Thread(this::record).start(); } @@ -91,6 +106,44 @@ public void stop() { stopEncode = true; } + public boolean isDevicesSupportAEC() { + return AcousticEchoCanceler.isAvailable(); + } + + private boolean initAEC(int audioSession) { + + boolean isDevicesSupportAEC = isDevicesSupportAEC(); + Log.e(TAG, "isDevicesSupportAEC: "+isDevicesSupportAEC); + if (!isDevicesSupportAEC) { + return false; + } + if (canceler != null) { + return false; + } + canceler = AcousticEchoCanceler.create(audioSession); + canceler.setEnabled(true); + return canceler.getEnabled(); + } + + public boolean isDevicesSupportAGC() { + return AutomaticGainControl.isAvailable(); + } + + private boolean initAGC(int audioSession) { + + boolean isDevicesSupportAGC = isDevicesSupportAGC(); + Log.e(TAG, "isDevicesSupportAGC: "+isDevicesSupportAGC); + if (!isDevicesSupportAGC) { + return false; + } + if (control != null) { + return false; + } + control = AutomaticGainControl.create(audioSession); + control.setEnabled(true); + return control.getEnabled(); + } + private void release() { if (audioRecord != null) { audioRecord.stop(); @@ -103,6 +156,18 @@ private void release() { audioCodec.release(); audioCodec = null; } + + if (canceler != null) { + canceler.setEnabled(false); + canceler.release(); + canceler = null; + } + + if (control != null) { + control.setEnabled(false); + control.release(); + control = null; + } } private void addADTStoPacket(ByteBuffer outputBuffer) { @@ -138,7 +203,6 @@ private void addADTStoPacket(byte[] packet, int packetLen) { packet[6] = (byte) 0xFC; } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void record() { if (audioCodec == null) { return; @@ -156,7 +220,12 @@ private void record() { // 将 AudioRecord 获取的 PCM 原始数据送入编码器 int audioInputBufferId = audioCodec.dequeueInputBuffer(0); if (audioInputBufferId >= 0) { - ByteBuffer inputBuffer = audioCodec.getInputBuffer(audioInputBufferId); + ByteBuffer inputBuffer = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + inputBuffer = audioCodec.getInputBuffer(audioInputBufferId); + } else { + inputBuffer = audioCodec.getInputBuffers()[audioInputBufferId]; + } int readSize = -1; if (inputBuffer != null) { readSize = audioRecord.read(inputBuffer, bufferSizeInBytes); @@ -168,7 +237,12 @@ private void record() { int audioOutputBufferId = audioCodec.dequeueOutputBuffer(audioInfo, 0); while (audioOutputBufferId >= 0) { - ByteBuffer outputBuffer = audioCodec.getOutputBuffer(audioOutputBufferId); + ByteBuffer outputBuffer = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + outputBuffer = audioCodec.getOutputBuffer(audioOutputBufferId); + } else { + outputBuffer = audioCodec.getOutputBuffers()[audioOutputBufferId]; + } outputBuffer.position(audioInfo.offset); outputBuffer.limit(audioInfo.offset + audioInfo.size); addADTStoPacket(outputBuffer); diff --git a/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/VideoEncoder.java b/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/VideoEncoder.java index 19bd19310..0193b0819 100644 --- a/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/VideoEncoder.java +++ b/sdk/video-link-android/src/main/java/com/tencent/iot/video/link/encoder/VideoEncoder.java @@ -4,8 +4,11 @@ import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.os.Build; +import android.os.Bundle; import android.util.Log; +import androidx.annotation.RequiresApi; + import com.tencent.iot.video.link.listener.OnEncodeListener; import com.tencent.iot.video.link.param.VideoEncodeParam; @@ -19,8 +22,10 @@ public class VideoEncoder { private final VideoEncodeParam videoEncodeParam; private final ExecutorService executor = Executors.newSingleThreadExecutor(); private MediaCodec mediaCodec; + private MediaFormat mediaFormat; private OnEncodeListener encoderListener; private long seq = 0L; + private int MAX_BITRATE_LENGTH = 1000000; public VideoEncoder(VideoEncodeParam param) { this.videoEncodeParam = param; @@ -34,7 +39,11 @@ private void initMediaCodec() { //TODO 因为获取到的视频帧数据是逆时针旋转了90度的,所以这里宽高需要对调 MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", videoEncodeParam.getHeight(), videoEncodeParam.getWidth()); //描述平均位速率(以位/秒为单位)的键。 关联的值是一个整数 - mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, videoEncodeParam.getBitRate()); + int bitRate = videoEncodeParam.getBitRate(); + if (bitRate > MAX_BITRATE_LENGTH) { + bitRate = MAX_BITRATE_LENGTH; + } + mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); //描述视频格式的帧速率(以帧/秒为单位)的键。帧率,一般在15至30之内,太小容易造成视频卡顿。 mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, videoEncodeParam.getFrameRate()); //色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同 @@ -56,6 +65,32 @@ private void initMediaCodec() { } } + //描述平均位速率(以位/秒为单位)的键。 关联的值是一个整数 + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + public void setVideoBitRate(int bitRate) { + int nowBitrate = videoEncodeParam.getBitRate(); + int nowWidth = videoEncodeParam.getWidth(); + int nowHeight = videoEncodeParam.getHeight(); + + if ((bitRate > nowWidth * nowHeight) || (bitRate < 10000) || (nowBitrate == bitRate) || (bitRate > MAX_BITRATE_LENGTH)) { + return; + } + + videoEncodeParam.setBitRate(bitRate); + + try { + Bundle params = new Bundle(); + params.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bitRate); + mediaCodec.setParameters(params); + + } catch (IllegalStateException e) { + Log.e("TAG", "updateBitrate failed", e); + } + } + + public int getVideoBitRate() { + return videoEncodeParam.getBitRate(); + } /** * 将NV21编码成H264 */