JLBA202505130001_关于吉林银行新建AI智能培训系统的需求_视频通话显示视频第一次上传

This commit is contained in:
田岩
2025-12-23 17:50:11 +08:00
parent f74c981b2f
commit 88ff54a5d7
219 changed files with 2459 additions and 1530 deletions
@@ -0,0 +1,24 @@
package com.example.ty_camera
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.ty_camera.test", appContext.packageName)
}
}
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
@@ -0,0 +1,408 @@
@file:Suppress("UNCHECKED_CAST", "USELESS_CAST", "INAPPLICABLE_JVM_NAME", "UNUSED_ANONYMOUS_PARAMETER", "NAME_SHADOWING", "UNNECESSARY_NOT_NULL_ASSERTION")
package uts.sdk.modules.tyCamera
import android.content.Context
import android.graphics.Bitmap
import android.graphics.ImageFormat
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CaptureRequest
import android.media.Image
import android.media.ImageReader
import android.os.Handler
import android.os.HandlerThread
import android.view.Surface
import io.dcloud.uniapp.*
import io.dcloud.uniapp.extapi.*
import io.dcloud.uts.*
import io.dcloud.uts.Map
import io.dcloud.uts.Set
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import io.dcloud.uts.UTSAndroid
open class MyApiOptions (
@JsonNotNull
open var paramA: Boolean = false,
open var success: ((res: String) -> Unit)? = null,
open var fail: ((res: MyApiFail) -> Unit)? = null,
open var complete: ((res: Any) -> Unit)? = null,
) : UTSObject()
typealias MyApiErrorCode = Number
interface MyApiFail : IUniError {
override var errCode: MyApiErrorCode
}
typealias CameraFacingType = String
open class CameraHelper {
private var context: Context
private var cameraManager: CameraManager
private var currentCameraId: String? = null
private var totalRotation: Number = 0
constructor(context: Context){
this.context = context
this.cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
if (this.cameraManager == null) {
throw UTSError("CameraHelper: 获取CameraManager失败,请检查摄像头权限或设备支持性")
}
}
public open fun getCameraIdByFacing(facing: CameraFacingType): String {
try {
val cameraIds = this.cameraManager.getCameraIdList()
if (cameraIds.size === 0) {
console.error("CameraHelper: 无可用摄像头ID")
throw UTSError()
}
var targetCameraId: String? = null
for(id in resolveUTSValueIterator(cameraIds)){
val characteristics = this.cameraManager.getCameraCharacteristics(id)
val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
if (lensFacing !== null && lensFacing === (if (facing === "BACK") {
CameraCharacteristics.LENS_FACING_BACK
} else {
CameraCharacteristics.LENS_FACING_FRONT
}
)) {
targetCameraId = id
break
}
}
if (targetCameraId === null) {
throw UTSError()
}
console.log("CameraHelper: \u6210\u529F\u83B7\u53D6" + (if (facing === "BACK") {
"后置"
} else {
"前置"
}
) + "\u6444\u50CF\u5934ID\uFF1A" + targetCameraId)
return targetCameraId
}
catch (e: Throwable) {
console.error("CameraHelper: \u83B7\u53D6" + (if (facing === "BACK") {
"后置"
} else {
"前置"
}
) + "\u6444\u50CF\u5934ID\u5F02\u5E38\uFF1A", e.message)
throw UTSError()
}
}
public open fun openCameraByFacing(facing: CameraFacingType, callback: CameraDevice.StateCallback, handler: Handler? = null): Unit {
var cameraId: String
try {
cameraId = this.getCameraIdByFacing(facing)
}
catch (e: Throwable) {
throw UTSError()
}
val characteristics = this.cameraManager.getCameraCharacteristics(cameraId)
val streamConfigurationMap = characteristics.get(android.hardware.camera2.CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
if (streamConfigurationMap !== null) {
val supportedSizes = streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888)
for(size in resolveUTSValueIterator(supportedSizes)){
console.log(object : UTSJSONObject() {
var width = size.getWidth()
var height = size.getHeight()
})
}
}
this.cameraManager.openCamera(cameraId, callback, handler)
}
public open fun closeCamera(): Unit {}
public open fun getCurrentCameraId(): String? {
return this.currentCameraId
}
public open fun getTotalRotation(): Number {
return this.totalRotation
}
private fun getBackCameraId(cameraIds: UTSArray<String>): String? {
for(id in resolveUTSValueIterator(cameraIds)){
val characteristics = this.cameraManager.getCameraCharacteristics(id)
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
if (facing !== null && facing === CameraCharacteristics.LENS_FACING_BACK) {
return id
}
}
return null
}
private fun calculateCameraRotation(cameraId: String): Unit {}
public open fun release(): Unit {
this.currentCameraId = null
this.totalRotation = 0
console.log("CameraHelper: 摄像头辅助类资源已释放")
}
}
val width: Int = 720
val height: Int = 480
var backgroundHandler: Handler? = null
var handlerThread: HandlerThread? = null
var imageReader: ImageReader? = null
var captureSession: CameraCaptureSession? = null
var cameraDevice: CameraDevice? = null
val runBlock1 = run {
console.log("1111", android.os.Build.VERSION.SDK_INT)
}
fun yuvToJpegBase64(image: android.media.Image): String {
val width = image.getWidth()
val height = image.getHeight()
if (image.getFormat() !== android.graphics.ImageFormat.YUV_420_888) {
console.error("仅支持YUV_420_888格式")
return ""
}
val planes = image.getPlanes()
val yPlane = planes[0]
val uPlane = planes[1]
val vPlane = planes[2]
val yRowStride = yPlane.getRowStride()
val yPixelStride = yPlane.getPixelStride()
val uRowStride = uPlane.getRowStride()
val uPixelStride = uPlane.getPixelStride()
val vRowStride = vPlane.getRowStride()
val vPixelStride = vPlane.getPixelStride()
val yBuffer = yPlane.getBuffer()
val uBuffer = uPlane.getBuffer()
val vBuffer = vPlane.getBuffer()
val yByteArray = ByteArray(yBuffer.remaining())
val uByteArray = ByteArray(uBuffer.remaining())
val vByteArray = ByteArray(vBuffer.remaining())
yBuffer.get(yByteArray)
uBuffer.get(uByteArray)
vBuffer.get(vByteArray)
val nv21 = ByteArray(width * height * 3 / 2)
var nv21Index: Int = 0
run {
var i: Int = 0
while(i < height){
run {
var j: Int = 0
while(j < width){
nv21[nv21Index++] = yByteArray[i * yRowStride + j * yPixelStride]
j++
}
}
i++
}
}
val halfHeight = Math.floor(height / 2)
val halfWidth = Math.floor(width / 2)
run {
var i: Int = 0
while(i < halfHeight){
run {
var j: Int = 0
while(j < halfWidth){
val uIndex: Int = i * uRowStride + j * uPixelStride
val vIndex: Int = i * vRowStride + j * vPixelStride
nv21[nv21Index++] = vByteArray[vIndex]
nv21[nv21Index++] = uByteArray[uIndex]
j++
}
}
i++
}
}
try {
val yuvImage = android.graphics.YuvImage(nv21, android.graphics.ImageFormat.NV21, width, height, null)
val outputStream = java.io.ByteArrayOutputStream()
val compressSuccess = yuvImage.compressToJpeg(android.graphics.Rect(0, 0, width, height), 80, outputStream)
if (!compressSuccess) {
console.error("YUV压缩为JPEG失败")
outputStream.close()
return ""
}
val jpegBytes = outputStream.toByteArray()
val srcBitmap: Bitmap = android.graphics.BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.size)
val matrix = android.graphics.Matrix()
matrix.postRotate((-90 as Number).toFloat())
val outputStream2 = java.io.ByteArrayOutputStream()
val rotatedBitmap = android.graphics.Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true)
rotatedBitmap.compress(android.graphics.Bitmap.CompressFormat.JPEG, 80, outputStream2)
val BitmapBytes = outputStream2.toByteArray()
val base64Raw = android.util.Base64.encodeToString(BitmapBytes, android.util.Base64.DEFAULT)
val base64Jpeg = "data:image/jpeg;base64," + base64Raw
outputStream.close()
return base64Jpeg
}
catch (e: Throwable) {
console.error("YUV转JPEG/Base64失败:", e)
return ""
}
}
fun startCameraPreview(options: MyApiOptions): Unit {
val context = UTSAndroid.getAppContext()
val activity = UTSAndroid.getUniActivity()
if (context == null || activity == null) {
console.error("错误:上下文或Activity为空")
return
}
handlerThread = HandlerThread("CameraBackground", -8)
handlerThread!!!!.start()
backgroundHandler = Handler(handlerThread!!!!.getLooper())
val cameraHelper = CameraHelper(context)
val totalRotation = cameraHelper.getTotalRotation()
try {
console.log("width, height", width, height)
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 8)
val localImageReader = imageReader
if (localImageReader == null) {
console.error("ImageReader 创建失败,无法设置监听器")
return
}
val imageAvailableListener = fun(reader: android.media.ImageReader): Unit {
val imageProxy: Image? = reader.acquireLatestImage()
if (imageProxy === null) {
return
}
options.success?.invoke(yuvToJpegBase64(imageProxy))
imageProxy.close()
return
}
localImageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler)
open class CustomCameraStateCallback : android.hardware.camera2.CameraDevice.StateCallback {
public constructor() : super() {}
override fun onOpened(device: android.hardware.camera2.CameraDevice): Unit {
console.log("相机打开成功")
cameraDevice = device
val localCameraDevice = device
val surface = imageReader!!!!.getSurface()
val surfaces = utsArrayOf(
surface
)
open class CustomCaptureSessionCallback : android.hardware.camera2.CameraCaptureSession.StateCallback {
private var localCameraDevice: android.hardware.camera2.CameraDevice
private var surface: android.view.Surface
public constructor(cameraDevice: android.hardware.camera2.CameraDevice, surface: android.view.Surface) : super() {
this.localCameraDevice = cameraDevice
this.surface = surface
}
override fun onConfigured(session: android.hardware.camera2.CameraCaptureSession): Unit {
console.log("采集会话配置成功,启动持续帧采集")
captureSession = session
val requestBuilder = this.localCameraDevice.createCaptureRequest(android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW)
requestBuilder.addTarget(this.surface)
requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, 270)
session.setRepeatingRequest(requestBuilder.build(), null, backgroundHandler)
}
override fun onConfigureFailed(session: android.hardware.camera2.CameraCaptureSession): Unit {
console.error("采集会话配置失败")
captureSession = null
}
}
val sessionCallback = CustomCaptureSessionCallback(localCameraDevice, surface) as CameraCaptureSession.StateCallback
localCameraDevice.createCaptureSession(surfaces, sessionCallback, backgroundHandler)
}
override fun onDisconnected(device: android.hardware.camera2.CameraDevice): Unit {
console.log("相机连接断开")
this.releaseCameraResources()
}
override fun onError(device: android.hardware.camera2.CameraDevice, p1: Int): Unit {
console.error("\u76F8\u673A\u6253\u5F00\u5931\u8D25")
this.releaseCameraResources()
}
override fun onClosed(device: android.hardware.camera2.CameraDevice): Unit {
console.log("相机已关闭")
super.onClosed(device)
}
private fun releaseCameraResources(): Unit {
if (cameraDevice != null) {
cameraDevice!!!!.close()
cameraDevice = null
console.log("相机资源已释放")
}
}
}
val cameraStateCallback = CustomCameraStateCallback()
cameraHelper.openCameraByFacing("FRONT", cameraStateCallback, backgroundHandler)
}
catch (e: Throwable) {
console.error("启动摄像头失败:", e)
}
}
fun stopCameraPreview(): Unit {
try {
console.log("开始释放摄像头资源")
if (captureSession != null) {
try {
captureSession!!!!.stopRepeating()
captureSession!!!!.abortCaptures()
captureSession!!!!.close()
console.log("采集会话已释放")
}
catch (e: Throwable) {
console.warn("释放采集会话时出现异常:", e)
}
finally{
captureSession = null
}
}
if (cameraDevice != null) {
try {
cameraDevice!!!!.close()
console.log("相机设备已关闭")
}
catch (e: Throwable) {
console.warn("关闭相机设备时出现异常:", e)
}
finally{
cameraDevice = null
}
}
if (imageReader != null) {
try {
imageReader!!!!.close()
console.log("ImageReader已释放")
}
catch (e: Throwable) {
console.warn("释放ImageReader时出现异常:", e)
}
finally{
imageReader = null
}
}
if (handlerThread != null) {
try {
if (backgroundHandler != null) {
console.log("先移除所有待处理的消息")
backgroundHandler!!!!.removeCallbacksAndMessages(null)
backgroundHandler = null
}
handlerThread!!!!.quitSafely()
handlerThread!!!!.join()
console.log("后台线程已停止")
}
catch (e: Throwable) {
console.warn("停止后台线程时出现异常:", e)
}
finally{
handlerThread = null
}
}
console.log("摄像头资源释放完成")
}
catch (e: Throwable) {
console.error("释放摄像头资源时发生全局异常:", e)
}
}
open class MyApiOptionsJSONObject : UTSJSONObject() {
open var paramA: Boolean = false
open var success: UTSCallback? = null
open var fail: UTSCallback? = null
open var complete: UTSCallback? = null
}
fun startCameraPreviewByJs(options: MyApiOptionsJSONObject): Unit {
return startCameraPreview(MyApiOptions(paramA = options.paramA, success = fun(res: String): Unit {
options.success?.invoke(res)
}
, fail = fun(res: MyApiFail): Unit {
options.fail?.invoke(res)
}
, complete = fun(res: Any): Unit {
options.complete?.invoke(res)
}
))
}
fun stopCameraPreviewByJs(): Unit {
return stopCameraPreview()
}
@@ -0,0 +1,17 @@
package com.example.ty_camera
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}