diff --git a/library/src/main/java/com/pedro/library/base/StreamBase.kt b/library/src/main/java/com/pedro/library/base/StreamBase.kt index c9b5bb33d..e203e3355 100644 --- a/library/src/main/java/com/pedro/library/base/StreamBase.kt +++ b/library/src/main/java/com/pedro/library/base/StreamBase.kt @@ -107,8 +107,11 @@ abstract class StreamBase( */ @Throws(IllegalArgumentException::class) @JvmOverloads - fun prepareVideo(width: Int, height: Int, bitrate: Int, fps: Int = 30, iFrameInterval: Int = 2, - rotation: Int = 0, profile: Int = -1, level: Int = -1, recordWidth: Int = width, recordHeight: Int = height, recordBitrate: Int = bitrate): Boolean { + fun prepareVideo( + width: Int, height: Int, bitrate: Int, fps: Int = 30, iFrameInterval: Int = 2, + rotation: Int = 0, profile: Int = -1, level: Int = -1, + recordWidth: Int = width, recordHeight: Int = height, recordBitrate: Int = bitrate + ): Boolean { if (isStreaming || isRecording || isOnPreview) { throw IllegalStateException("Stream, record and preview must be stopped before prepareVideo") } @@ -550,6 +553,10 @@ abstract class StreamBase( fun resetAudioEncoder(): Boolean = audioEncoder.reset() private fun prepareEncoders(): Boolean { + if (differentRecordResolution) { + val result = videoEncoderRecord.prepareVideoEncoder() + if (!result) return false + } return videoEncoder.prepareVideoEncoder() && audioEncoder.prepareAudioEncoder() } diff --git a/library/src/main/java/com/pedro/library/view/GlInterface.java b/library/src/main/java/com/pedro/library/view/GlInterface.java index 8984e0d98..4ef92c872 100644 --- a/library/src/main/java/com/pedro/library/view/GlInterface.java +++ b/library/src/main/java/com/pedro/library/view/GlInterface.java @@ -33,6 +33,8 @@ public interface GlInterface { */ void setEncoderSize(int width, int height); + void setEncoderRecordSize(int width, int height); + Point getEncoderSize(); /** * Get SurfaceTexture generated by Opengl. This should be called after start render. @@ -58,6 +60,9 @@ public interface GlInterface { */ void removeMediaCodecSurface(); + void addMediaCodecRecordSurface(Surface surface); + + void removeMediaCodecRecordSurface(); /** * Capture an Image from Opengl. * diff --git a/library/src/main/java/com/pedro/library/view/GlStreamInterface.kt b/library/src/main/java/com/pedro/library/view/GlStreamInterface.kt index 4c1ea629e..d3f241a38 100644 --- a/library/src/main/java/com/pedro/library/view/GlStreamInterface.kt +++ b/library/src/main/java/com/pedro/library/view/GlStreamInterface.kt @@ -93,7 +93,7 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener, encoderHeight = height } - fun setEncoderRecordSize(width: Int, height: Int) { + override fun setEncoderRecordSize(width: Int, height: Int) { encoderRecordWidth = width encoderRecordHeight = height } @@ -146,7 +146,7 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener, } } - fun addMediaCodecRecordSurface(surface: Surface) { + override fun addMediaCodecRecordSurface(surface: Surface) { executor?.secureSubmit { if (surfaceManager.isReady) { surfaceManagerEncoderRecord.release() @@ -155,7 +155,7 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener, } } - fun removeMediaCodecRecordSurface() { + override fun removeMediaCodecRecordSurface() { threadQueue.clear() executor?.secureSubmit { surfaceManagerEncoderRecord.release() diff --git a/library/src/main/java/com/pedro/library/view/OpenGlView.java b/library/src/main/java/com/pedro/library/view/OpenGlView.java index 44aef00ba..9dea65260 100644 --- a/library/src/main/java/com/pedro/library/view/OpenGlView.java +++ b/library/src/main/java/com/pedro/library/view/OpenGlView.java @@ -60,10 +60,12 @@ public class OpenGlView extends SurfaceView private final SurfaceManager surfaceManagerPhoto = new SurfaceManager(); private final SurfaceManager surfaceManager = new SurfaceManager(); private final SurfaceManager surfaceManagerEncoder = new SurfaceManager(); + private final SurfaceManager surfaceManagerEncoderRecord = new SurfaceManager(); private final BlockingQueue filterQueue = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue threadQueue = new LinkedBlockingQueue<>(); private int previewWidth, previewHeight; private int encoderWidth, encoderHeight; + private int encoderRecordWidth, encoderRecordHeight; private TakePhotoCallback takePhotoCallback; private int streamRotation; private boolean muteVideo = false; @@ -224,6 +226,12 @@ public void setEncoderSize(int width, int height) { this.encoderHeight = height; } + @Override + public void setEncoderRecordSize(int width, int height) { + this.encoderRecordWidth = width; + this.encoderRecordHeight = height; + } + @Override public Point getEncoderSize() { return new Point(encoderWidth, encoderHeight); @@ -267,6 +275,15 @@ private void draw(boolean forced) { streamRotation, isStreamVerticalFlip, isStreamHorizontalFlip); surfaceManagerEncoder.swapBuffer(); } + // render VideoEncoder (record if the resolution is different than stream) + if (surfaceManagerEncoderRecord.isReady() && mainRender.isReady() && !limitFps) { + int w = muteVideo ? 0 : encoderRecordWidth; + int h = muteVideo ? 0 : encoderRecordHeight; + surfaceManagerEncoderRecord.makeCurrent(); + mainRender.drawScreen(w, h, aspectRatioMode, + streamRotation, isStreamVerticalFlip, isStreamHorizontalFlip); + surfaceManagerEncoderRecord.swapBuffer(); + } if (takePhotoCallback != null && surfaceManagerPhoto.isReady() && mainRender.isReady()) { surfaceManagerPhoto.makeCurrent(); mainRender.drawScreen(encoderWidth, encoderHeight, aspectRatioMode, @@ -283,10 +300,8 @@ public void addMediaCodecSurface(Surface surface) { if (executor == null) return; ExtensionsKt.secureSubmit(executor, () -> { if (surfaceManager.isReady()) { - surfaceManagerPhoto.release(); surfaceManagerEncoder.release(); surfaceManagerEncoder.eglSetup(surface, surfaceManager); - surfaceManagerPhoto.eglSetup(encoderWidth, encoderHeight, surfaceManagerEncoder); } return null; }); @@ -298,9 +313,31 @@ public void removeMediaCodecSurface() { ExecutorService executor = this.executor; if (executor == null) return; ExtensionsKt.secureSubmit(executor, () -> { - surfaceManagerPhoto.release(); surfaceManagerEncoder.release(); - surfaceManagerPhoto.eglSetup(encoderWidth, encoderHeight, surfaceManager); + return null; + }); + } + + @Override + public void addMediaCodecRecordSurface(Surface surface) { + ExecutorService executor = this.executor; + if (executor == null) return; + ExtensionsKt.secureSubmit(executor, () -> { + if (surfaceManager.isReady()) { + surfaceManagerEncoderRecord.release(); + surfaceManagerEncoderRecord.eglSetup(surface, surfaceManager); + } + return null; + }); + } + + @Override + public void removeMediaCodecRecordSurface() { + threadQueue.clear(); + ExecutorService executor = this.executor; + if (executor == null) return; + ExtensionsKt.secureSubmit(executor, () -> { + surfaceManagerEncoderRecord.release(); return null; }); } @@ -338,6 +375,7 @@ public void stop() { forceRenderer.stop(); surfaceManagerPhoto.release(); surfaceManagerEncoder.release(); + surfaceManagerEncoderRecord.release(); surfaceManager.release(); mainRender.release(); return null;