安卓实现视频录制与显示和翻转摄像头

权限:

<!-- 相机权限 -->
<uses-featureandroid:name="android.hardware.camera"android:required="false" />
<uses-permission android:name="android.permission.CAMERA" /><!-- 录音权限(包括麦克风权限) -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextureViewandroid:id="@+id/textureView"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toTopOf="@id/switchCameraButton"/><Buttonandroid:id="@+id/switchCameraButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="翻转摄像头"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"android:layout_marginBottom="16dp"/></androidx.constraintlayout.widget.ConstraintLayout>

Activity:

package com.xmkjsoft.video_call;import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.webrtc.MediaStream;import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;public class MainActivity extends AppCompatActivity {private MyWebSocketClient webSocketClient;private static final int PERMISSION_REQUEST_CAMERA = 1;private static final int PERMISSION_REQUEST_RECORD_AUDIO = 2;private static final int REQUEST_CAMERA_PERMISSION = 200;private TextureView textureView;private CameraDevice cameraDevice;private CaptureRequest.Builder captureRequestBuilder;private CameraCaptureSession cameraCaptureSession;private String cameraId;private MediaRecorder mediaRecorder;// 储存视频的文件路径private static final String VIDEO_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/video.mp4";// 默认无参数构造函数public MainActivity() {}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 检查并请求相机权限if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},PERMISSION_REQUEST_CAMERA);}// 检查并请求录音权限(包括麦克风权限)if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECORD_AUDIO},PERMISSION_REQUEST_RECORD_AUDIO);}// 设置按钮点击事件监听器Button switchCameraButton = findViewById(R.id.switchCameraButton);switchCameraButton.setOnClickListener(v -> {if (cameraDevice != null) {closeCamera();// 切换摄像头cameraId = (cameraId.equals("0")) ? "1" : "0"; // 更新 cameraIdopenCamera(); // 重新打开摄像头}});// 获取本地视频流textureView = findViewById(R.id.textureView);textureView.setSurfaceTextureListener(textureListener);// 初始化 MediaRecordermediaRecorder = new MediaRecorder();mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);mediaRecorder.setOutputFile(VIDEO_FILE_PATH);connectWebSocket();}private void connectWebSocket() {try {webSocketClient = new MyWebSocketClient("ws://192.168.28.218/ws/1233");webSocketClient.connect();} catch (URISyntaxException e) {e.printStackTrace();}}// 内部类,用于处理 WebSocket 连接状态和消息private class MyWebSocketClient extends WebSocketClient {public MyWebSocketClient(String serverUri) throws URISyntaxException {super(new java.net.URI(serverUri));}@Overridepublic void onOpen(ServerHandshake handshakedata) {// WebSocket 连接已打开System.out.println("WebSocket 连接已打开");}@Overridepublic void onMessage(String message) {// 收到文本消息System.out.println("收到文本消息:" + message);}@Overridepublic void onClose(int code, String reason, boolean remote) {// WebSocket 连接已关闭System.out.println("WebSocket 连接已关闭,code:" + code + ", reason:" + reason + ", remote:" + remote);}@Overridepublic void onError(Exception ex) {// WebSocket 连接出错System.out.println("WebSocket 连接出错:" + ex.getMessage());}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == PERMISSION_REQUEST_CAMERA) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {// 相机权限已授予System.out.println("相机权限已授予");} else {// 相机权限被拒绝System.out.println("相机权限被拒绝");}} else if (requestCode == PERMISSION_REQUEST_RECORD_AUDIO) {if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {// 录音权限已授予System.out.println("录音权限已授予");} else {// 录音权限被拒绝System.out.println("录音权限被拒绝");}}}private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {openCamera();}@Overridepublic void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {}@Overridepublic boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {return false;}@Overridepublic void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {}};// 打开相机private void openCamera() {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);try {// 检查 cameraId 是否为空if (cameraId == null) {// 如果为空,选择默认摄像头cameraId = manager.getCameraIdList()[0];}if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);return;}manager.openCamera(cameraId, stateCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {cameraDevice = camera;createCameraPreview();}@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {cameraDevice.close();}@Overridepublic void onError(@NonNull CameraDevice camera, int i) {cameraDevice.close();cameraDevice = null;}};private void createCameraPreview() {try {SurfaceTexture texture = textureView.getSurfaceTexture();texture.setDefaultBufferSize(1920, 1080);Surface surface = new Surface(texture);captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);captureRequestBuilder.addTarget(surface);cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {if (cameraDevice == null) {return;}MainActivity.this.cameraCaptureSession = cameraCaptureSession;try {// 开始预览MainActivity.this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);// 添加 MediaRecorder 的 Surfaceif (mediaRecorder != null) {captureRequestBuilder.addTarget(mediaRecorder.getSurface());// 开始录制视频mediaRecorder.start();}} catch (CameraAccessException | IllegalStateException e) {e.printStackTrace();}}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show();}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}// 在 onStop() 方法中停止录制视频@Overrideprotected void onStop() {super.onStop();stopRecording();}private void stopRecording() {if (mediaRecorder != null) {try {mediaRecorder.stop();mediaRecorder.reset();mediaRecorder.release();} catch (RuntimeException e) {e.printStackTrace();}}}// 关闭相机private void closeCamera() {if (cameraCaptureSession != null) {cameraCaptureSession.close();cameraCaptureSession = null;}if (cameraDevice != null) {cameraDevice.close();cameraDevice = null;}}
}

运行效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/9593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024好用的网页客服系统推荐?

2024好用的网页客服系统推荐&#xff1f;Zoho SalesIQ是一款强大的实时聊天工具&#xff0c;专为网站和在线商店设计。它提供了一套全面的功能&#xff0c;帮助企业实时解决客户问题&#xff0c;提高转化率和客户满意度。 实时监控 Zoho SalesIQ能够实时监控网站的访问者活动&…

能源系统升级BACnet IP分布式I/O边缘模块深度整合

能源管理系统(EMS)的高效运行成为了实现绿色建筑、节能减排的关键。而BACnet IP分布式远程I/O模块作为这一系统中的重要组件&#xff0c;正发挥着不可小觑的作用。本文将以某大型商业综合体为例&#xff0c;探讨BACnet IP I/O模块如何在能源管理中大显身手。 商业综合体涵盖办公…

波分系统中的EDFA光纤放大器

功能&#xff1a; 实现C波段光信号整体放大总波长范围覆盖1528~1565nm支持系统实现不同跨段的无电中继传亮点&#xff1a; 宽增益范围&#xff1a;1528nm~1565nm三种光放大器C波段应用&#xff1a; BA功率放大器LA线路放大器PA前置放大器 低噪声系数&#xff0c;典型值&#xf…

一文教你在windows上实现ollama+open webui、外网访问本地模型、ollama使用GPU加速

前言&#xff1a; ollama工具的出现让大语言模型的部署变得格外的轻松&#xff0c;但是在windows系统部署之后发现无法使用GPU进行加速&#xff0c;通过多方面查找资料发现可以在docker中使用命令启用GPU加速。另外通过Docker也可以快速部署open webui,于是本文基于docker实现…

cmake进阶:文件操作之写文件

一. 简介 cmake 提供了 file() 命令可对文件进行一系列操作&#xff0c;譬如读写文件、删除文件、文件重命名、拷贝文件、创建目录等等。 接下来 学习这个功能强大的 file() 命令。 本文学习 CMakeLists.txt语法中写文件操作。 二. cmake进阶&#xff1a;文件操作之写文件…

【活动】如何通过AI技术提升内容生产的效率与质量

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 如何通过AI技术提升内容生产的效率与质量引言一、自然语言处理&#xff08;NLP&…

预约咨询小程序源码搭建/部署/上线/运营/售后/更新

包含在线咨询、视频咨询、电话咨询、面询多种咨询方式&#xff0c;适用于心理、法律、宠物等预约咨询问诊场景 分类预览&#xff1a;小程序提供清晰的分类选项&#xff0c;使用户能够迅速找到所需的咨询服务类型&#xff0c;如法律咨询、心理咨询、医疗咨询等。预约时间选择&a…

HTML_CSS学习:定位

一、相对定位 相关代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>相对定位</title><style>.outer{width: 500px;background-color: #999ff0;border: 1px solid #000;p…

网线 网口 绿灯:链路连接,黄灯:数据信号 ——网络

正常情况&#xff1a;绿灯常亮&#xff0c;橙色常亮或闪烁。有信号传输时闪烁&#xff0c;没信号时常亮。 绿灯是链路指示&#xff08;即连接&#xff09;&#xff0c;黄灯是信号指示&#xff08;即传数据&#xff09; 一.分情况说明: 1.黄灯闪动,绿灯长亮:网线正常,正在通信中…

十四、网络编程

目录 一、网络编程概述二、网络通讯要素1、IP和端口号2、网络通信协议 三、IP和端口号四、网络协议1、网络通信协议2、TCP/IP协议簇1&#xff09;TCP协议2&#xff09;UDP 3、Socket 五、TCP网络编程1、基于Socket的TCP编程1&#xff09;客户端创建socket对象2&#xff09; 服务…

SQL运算符以及使用变量参与实际的查询(增删改)操作

#关系运算符&#xff08;<>!not&#xff09;与逻辑运算符&#xff08;&and|or&#xff09;set x7,y5;select x>y as TRUE,x<y as FALSE;#正确返回值true,实际返回值1&#xff0c;false0select xy;# 判断两个数值是否相等无需使用&#xff08;&#xff09;号&am…

HTML中插入图片(2024/5/10)

背景&#xff1a; 自己做了个小网站&#xff0c;想在网页的右下角贴上自己的微信二维码&#xff0c;用以下代码就可以了。 注意&#xff0c;这里是放右下角了&#xff0c;距离和二维码的图片大小需要自己去调整。 /*二维码的名字和路径需要自己修改*/ <!DOCTYPE html>…

C++初阶学习第六弹——string(1)——标准库中的string类

前言&#xff1a; 在前面&#xff0c;我们学习了C的类与对象&#xff0c;认识到了C与C语言的一些不同&#xff0c;今天&#xff0c;我们将进入C的 关键部分——STL&#xff0c;学习完这部分之后&#xff0c;我们就可以清楚的认识到C相比于C语言的快捷与便利 一、为什么有string…

获取文件夹下的vue文件形成组件,require.context

前言&#xff1a;项目中现有一个文件里面包含所有需要用到的组件&#xff0c;如果一个个的去import&#xff0c;则会非常麻烦&#xff0c;现有require.context去实现&#xff0c; 1、require.context var request require.context(‘./module’, true, /.js$/) require.cont…

AI编码工具-通义灵码功能实测(二)

AI编码工具-通义灵码功能实测&#xff08;二&#xff09; 通义灵码智能问答 在上一篇文章中&#xff1a;https://blog.csdn.net/csdn565973850/article/details/138563670?spm1001.2014.3001.5501 讲述了通义灵码的7大应用场景&#xff0c;这里在使用过程中遇到了一些问题&…

视频剪辑一键处理技巧:批量分割视频,快速提取m3u8视频

随着网络视频的普及和多样化&#xff0c;视频剪辑和处理成为了很多用户的基本需求。在众多的视频处理技巧中&#xff0c;批量分割视频快速提取m3u8视频是常见的操作。本文将介绍如何利用云炫AI智剪一键处理的技巧&#xff0c;轻松完成这些任务&#xff0c;提高视频剪辑的效率。…

Java中的包(package)是什么和如何使用它们

目录 一、什么是Java包&#xff1f; 二、为什么使用包&#xff1f; 三、如何创建和使用包 创建包 引入包 四、包的实际应用 总结 Java中的包&#xff08;package&#xff09;是一种用于组织相关类和接口的命名空间。通过将代码逻辑地分组&#xff0c;它们有助于维护大型…

安卓提示Cannot resolve symbol ‘BuildConfig‘

安卓提示Cannot resolve symbol BuildConfig build.gradle android {...defaultConfig {...versionName "1.1.2" // 这里设置版本号...}... }java代码使用 tv_version.setText(BuildConfig.VERSION_NAME) ; 提示错误 Cannot resolve symbol BuildConfig 解决办法 bu…

QT功能 实现静态内容国际化实验

文章目录 第一步&#xff1a;新建一个QT工程第二步&#xff1a;添加控件第三步&#xff1a;在pro文件中添加内容第四步&#xff1a;更新文件第五步&#xff1a;打开QT的Linguist第六步&#xff1a;添加翻译内容第七步&#xff1a;回到QT Creator中添加文件第八步&#xff1a;给…

初阶数据结构—顺序表和链表

第一章&#xff1a;线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就…