@@ -40,6 +40,7 @@ import com.pedro.encoder.utils.gl.GlUtil
4040import com.pedro.library.util.Filter
4141import com.pedro.library.util.SensorRotationManager
4242import java.util.concurrent.BlockingQueue
43+ import java.util.concurrent.ConcurrentHashMap
4344import java.util.concurrent.ExecutorService
4445import java.util.concurrent.LinkedBlockingQueue
4546import java.util.concurrent.atomic.AtomicBoolean
@@ -59,7 +60,35 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener,
5960 private val surfaceManagerEncoderRecord = SurfaceManager ()
6061 private val surfaceManagerPhoto = SurfaceManager ()
6162 private val surfaceManagerPreview = SurfaceManager ()
63+ private val multiPreviewSurfaceManagers = ConcurrentHashMap <Surface , PreviewSurfaceInfo >()
6264 private val mainRender = MainRender ()
65+
66+ /* *
67+ * User-facing configuration for a multi-preview surface.
68+ * All configuration fields are mutable to support dynamic updates.
69+ *
70+ * @param width the width of the preview. 0 to use preview or encoder resolution
71+ * @param height the height of the preview. 0 to use preview or encoder resolution
72+ * @param horizontalFlip true to flip horizontally
73+ * @param verticalFlip true to flip vertically
74+ * @param aspectRatioMode aspect ratio mode for this surface
75+ * @param isPortrait true for portrait orientation, false for landscape
76+ * @param viewPort viewport for this surface. null for full screen
77+ */
78+ data class MultiPreviewConfig (
79+ var width : Int = 0 ,
80+ var height : Int = 0 ,
81+ var horizontalFlip : Boolean = false ,
82+ var verticalFlip : Boolean = false ,
83+ var aspectRatioMode : AspectRatioMode = AspectRatioMode .Adjust ,
84+ var isPortrait : Boolean = false ,
85+ var viewPort : ViewPort ? = null
86+ )
87+
88+ data class PreviewSurfaceInfo (
89+ val surfaceManager : SurfaceManager ,
90+ val config : MultiPreviewConfig
91+ )
6392 private var encoderWidth = 0
6493 private var encoderHeight = 0
6594 private var encoderRecordWidth = 0
@@ -207,6 +236,10 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener,
207236 surfaceManagerPhoto.release()
208237 surfaceManagerEncoder.release()
209238 surfaceManagerEncoderRecord.release()
239+ multiPreviewSurfaceManagers.values.forEach { info ->
240+ info.surfaceManager.release()
241+ }
242+ multiPreviewSurfaceManagers.clear()
210243 surfaceManager.release()
211244 mainRender.release()
212245 }
@@ -292,6 +325,27 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener,
292325 surfaceManagerPreview.swapBuffer()
293326 }
294327 }
328+ // render extra multi-preview surfaces (using independent configuration from PreviewSurfaceInfo)
329+ if (multiPreviewSurfaceManagers.isNotEmpty() && mainRender.isReady() && ! limitFps) {
330+ // Only draw filters if default preview is not active (to avoid double drawing)
331+ if (! surfaceManagerPreview.isReady) {
332+ if (surfaceManager.makeCurrent()) {
333+ mainRender.drawFilters(true )
334+ surfaceManager.swapBuffer()
335+ }
336+ }
337+ val previewSnapshot = multiPreviewSurfaceManagers.values.toList()
338+ previewSnapshot.forEach { info ->
339+ if (info.surfaceManager.isReady) {
340+ if (info.surfaceManager.makeCurrent()) {
341+ // Each preview uses its own isPortrait and viewPort configuration
342+ mainRender.drawScreenPreview(info.config.width, info.config.height, info.config.isPortrait, info.config.aspectRatioMode, 0 ,
343+ info.config.verticalFlip, info.config.horizontalFlip, info.config.viewPort)
344+ info.surfaceManager.swapBuffer()
345+ }
346+ }
347+ }
348+ }
295349 }
296350
297351 override fun onFrameAvailable (surfaceTexture : SurfaceTexture ? ) {
@@ -353,6 +407,56 @@ class GlStreamInterface(private val context: Context): OnFrameAvailableListener,
353407 surfaceManagerPreview.release()
354408 }
355409
410+ /* *
411+ * Add a multi-preview surface
412+ * @param surface the surface to add
413+ * @param config configuration for the preview surface
414+ */
415+ fun addMultiPreviewSurface (surface : Surface , config : MultiPreviewConfig ) {
416+ if (surfaceManager.isReady) {
417+ multiPreviewSurfaceManagers.remove(surface)?.surfaceManager?.release()
418+
419+ val w = if (config.width > 0 ) config.width else if (previewWidth == 0 ) encoderWidth else previewWidth
420+ val h = if (config.height > 0 ) config.height else if (previewHeight == 0 ) encoderHeight else previewHeight
421+
422+ val surfaceMgr = SurfaceManager ()
423+ surfaceMgr.eglSetup(surface, surfaceManager)
424+ val finalConfig = MultiPreviewConfig (w, h, config.horizontalFlip, config.verticalFlip, config.aspectRatioMode, config.isPortrait, config.viewPort)
425+ multiPreviewSurfaceManagers[surface] = PreviewSurfaceInfo (surfaceMgr, finalConfig)
426+ }
427+ }
428+
429+ fun removeMultiPreviewSurface (surface : Surface ) {
430+ multiPreviewSurfaceManagers.remove(surface)?.surfaceManager?.release()
431+ }
432+
433+ fun removeAllMultiPreviewSurfaces () {
434+ multiPreviewSurfaceManagers.values.forEach { info ->
435+ info.surfaceManager.release()
436+ }
437+ multiPreviewSurfaceManagers.clear()
438+ }
439+
440+ fun updateMultiPreviewConfig (surface : Surface , config : MultiPreviewConfig ): Boolean {
441+ val info = multiPreviewSurfaceManagers[surface] ? : return false
442+
443+ info.config.width = if (config.width > 0 ) config.width else if (previewWidth == 0 ) encoderWidth else previewWidth
444+ info.config.height = if (config.height > 0 ) config.height else if (previewHeight == 0 ) encoderHeight else previewHeight
445+ info.config.horizontalFlip = config.horizontalFlip
446+ info.config.verticalFlip = config.verticalFlip
447+ info.config.aspectRatioMode = config.aspectRatioMode
448+ info.config.isPortrait = config.isPortrait
449+ info.config.viewPort = config.viewPort
450+
451+ return true
452+ }
453+
454+ fun hasMultiPreviewSurface (surface : Surface ): Boolean {
455+ return multiPreviewSurfaceManagers.containsKey(surface)
456+ }
457+
458+ fun getMultiPreviewSurfaceCount (): Int = multiPreviewSurfaceManagers.size
459+
356460 override fun setStreamRotation (orientation : Int ) {
357461 this .streamOrientation = orientation
358462 }
0 commit comments