正在显示
2 个修改的文件
包含
117 行增加
和
1 行删除
| @@ -62,7 +62,10 @@ internal constructor( | @@ -62,7 +62,10 @@ internal constructor( | ||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | /** | 64 | /** |
| 65 | - * Creates a video track, recording video through the supplied [capturer] | 65 | + * Creates a video track, recording video through the supplied [capturer]. |
| 66 | + * | ||
| 67 | + * This method will call [VideoCapturer.initialize] and handle the lifecycle of | ||
| 68 | + * [SurfaceTextureHelper]. | ||
| 66 | */ | 69 | */ |
| 67 | fun createVideoTrack( | 70 | fun createVideoTrack( |
| 68 | name: String = "", | 71 | name: String = "", |
livekit-android-sdk/src/main/java/io/livekit/android/room/track/video/BitmapFrameCapturer.kt
0 → 100644
| 1 | +import android.content.Context | ||
| 2 | +import android.graphics.Bitmap | ||
| 3 | +import android.graphics.Matrix | ||
| 4 | +import android.graphics.Paint | ||
| 5 | +import android.os.Build | ||
| 6 | +import android.view.Surface | ||
| 7 | +import org.webrtc.CapturerObserver | ||
| 8 | +import org.webrtc.SurfaceTextureHelper | ||
| 9 | +import org.webrtc.VideoCapturer | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * A [VideoCapturer] that can be manually driven by passing in [Bitmap]. | ||
| 13 | + * | ||
| 14 | + * Once [startCapture] is called, call [pushBitmap] to render images as video frames. | ||
| 15 | + */ | ||
| 16 | +open class BitmapFrameCapturer : VideoCapturer { | ||
| 17 | + private var surfaceTextureHelper: SurfaceTextureHelper? = null | ||
| 18 | + private var capturerObserver: CapturerObserver? = null | ||
| 19 | + private var disposed = false | ||
| 20 | + | ||
| 21 | + private var rotation = 0 | ||
| 22 | + private var width = 0 | ||
| 23 | + private var height = 0 | ||
| 24 | + | ||
| 25 | + private val stateLock = Any() | ||
| 26 | + | ||
| 27 | + private var surface: Surface? = null | ||
| 28 | + | ||
| 29 | + override fun initialize( | ||
| 30 | + surfaceTextureHelper: SurfaceTextureHelper, | ||
| 31 | + context: Context, | ||
| 32 | + observer: CapturerObserver, | ||
| 33 | + ) { | ||
| 34 | + synchronized(stateLock) { | ||
| 35 | + this.surfaceTextureHelper = surfaceTextureHelper | ||
| 36 | + this.capturerObserver = observer | ||
| 37 | + surface = Surface(surfaceTextureHelper.surfaceTexture) | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + private fun checkNotDisposed() { | ||
| 42 | + check(!disposed) { "Capturer is disposed." } | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + override fun startCapture(width: Int, height: Int, framerate: Int) { | ||
| 46 | + synchronized(stateLock) { | ||
| 47 | + checkNotDisposed() | ||
| 48 | + checkNotNull(surfaceTextureHelper) { "BitmapFrameCapturer must be initialized before calling startCapture." } | ||
| 49 | + capturerObserver?.onCapturerStarted(true) | ||
| 50 | + surfaceTextureHelper?.startListening { frame -> capturerObserver?.onFrameCaptured(frame) } | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + override fun stopCapture() { | ||
| 55 | + synchronized(stateLock) { | ||
| 56 | + surfaceTextureHelper?.stopListening() | ||
| 57 | + capturerObserver?.onCapturerStopped() | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + override fun changeCaptureFormat(width: Int, height: Int, framerate: Int) { | ||
| 62 | + // Do nothing. | ||
| 63 | + // These attributes are driven by the bitmaps fed in. | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + override fun dispose() { | ||
| 67 | + synchronized(stateLock) { | ||
| 68 | + if (disposed) { | ||
| 69 | + return | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + stopCapture() | ||
| 73 | + surface?.release() | ||
| 74 | + disposed = true | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + override fun isScreencast(): Boolean = false | ||
| 79 | + | ||
| 80 | + fun pushBitmap(bitmap: Bitmap, rotationDegrees: Int) { | ||
| 81 | + synchronized(stateLock) { | ||
| 82 | + if (disposed) { | ||
| 83 | + return | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + checkNotNull(surfaceTextureHelper) | ||
| 87 | + checkNotNull(surface) | ||
| 88 | + if (this.rotation != rotationDegrees) { | ||
| 89 | + surfaceTextureHelper?.setFrameRotation(rotationDegrees) | ||
| 90 | + this.rotation = rotationDegrees | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + if (this.width != bitmap.width || this.height != bitmap.height) { | ||
| 94 | + surfaceTextureHelper?.setTextureSize(bitmap.width, bitmap.height) | ||
| 95 | + this.width = bitmap.width | ||
| 96 | + this.height = bitmap.height | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + surfaceTextureHelper?.handler?.post { | ||
| 100 | + val canvas = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
| 101 | + surface?.lockHardwareCanvas() | ||
| 102 | + } else { | ||
| 103 | + surface?.lockCanvas(null) | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + if (canvas != null) { | ||
| 107 | + canvas.drawBitmap(bitmap, Matrix(), Paint()) | ||
| 108 | + surface?.unlockCanvasAndPost(canvas) | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | +} |
-
请 注册 或 登录 后发表评论