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

权限:

<!-- 相机权限 -->
<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.rhkb.cn/news/324356.html

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

相关文章

Centos 7.9 配置VNCServer实现远程vnc连接

文章目录 1、Centos安装图形界面1.1、安装X Windows System图形界面1.2、安装GNOME图形界面 2、VNC SERVER配置2.1、VNC SERVER安装2.2、VNC SERVER配置1&#xff09;创建vnc配置文件2&#xff09;修改配置文件内容3&#xff09;完整配置文件参考 2.3、设置vnc密码2.4、配置防火…

网络编程套接字和传输层tcp,udp协议

认识端口号 我们知道在网络数据传输的时候&#xff0c;在IP数据包头部有两个IP地址&#xff0c;分别叫做源IP地址和目的IP地址。IP地址是帮助我们在网络中确定最终发送的主机&#xff0c;但是实际上数据应该发送到主机上指定的进程上的&#xff0c;所以我们不仅要确定主机&…

虚拟化技术 分离虚拟机数据流量与ESXi的流量管理

一、实验内容 为ESXi主机添加网卡通过vClient查看已添加的网卡信息为ESXi添加网络&#xff0c;创建标准交换机修改网络配置&#xff0c;实现虚拟机数据流量与ESXi的管理流量分离 二、实验主要仪器设备及材料 安装有64位Windows操作系统的台式电脑或笔记本电脑&#xff0c;建…

泰达克仿钻点水晶饰品包装印刷防滑UV胶特性及应用场景

仿钻点UV滴胶是一种特殊的胶水 常用于模拟钻石的效果 它是一种透明的胶水 具有高光泽度和折射率 可以在物体表面形成类似钻石的亮闪效果 仿钻点UV滴胶通常由紫外线固化胶组成 需要通过紫外线照射来固化和硬化 它具有以下特点&#xff1a; 1. 透明度&#xff1a;仿钻点UV滴胶具有…

使用 OpenCV 创建视频(74)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV 库来捕获和处理视频输入和相似度测量(73) 下一篇&#xff1a;OpenCV使用 Kinect 和其他兼容 OpenNI 的深度传感器(75) 目标 每当您使用视频源时&#xff0c;您最终可能希望将图像处理结果保…

Zabbix6.0容器化部署(Docker-Composed)

Zabbix 为每个 Zabbix 组件提供 Docker image 作为可移植和自给自足的容器&#xff0c;以加快部署和更新过程。 Zabbix 组件在 Ubuntu、Alpine Linux 和 CentOS 基础 image 上提供:Zabbix 组件支持 MySQL 和 PostgreSQL 数据库、Apache2 和 Nginx Web 服务器。 1. Zabbix 组件…

ASP.NET网上车辆档案管理系统

摘 要 本文采用基于Web的Asp.net技术&#xff0c;并与sql server 2000数据库相结合&#xff0c;研发了一套车辆档案管理系统。该系统扩展性好&#xff0c;易于维护。简化了车辆档案设计流程&#xff0c;去除了冗余信息。汽车销售企业可以通过本系统完成整个销售及售后所有档案…

C语言指针的初级练习

前言 从0开始记录我的学习历程&#xff0c;我会尽我所能&#xff0c;写出最最大白话的文章&#xff0c;希望能够帮到你&#xff0c;谢谢。 提示&#xff1a;文章作者为初学者&#xff0c;有问题请评论指正&#xff0c;感谢。 哥们嗷 不知道你和我是否一样在学习C语言指针的时…

【ZZULI数据结构实验】压缩与解码的钥匙:赫夫曼编码应用

&#x1f4c3;博客主页&#xff1a; 小镇敲码人 &#x1f49a;代码仓库&#xff0c;欢迎访问 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f30f; 任尔江湖满血骨&#xff0c;我自踏雪寻梅香。 万千浮云遮碧…

使用 Docker 部署 TaleBook 私人书籍管理系统

1&#xff09;项目介绍 GitHub&#xff1a;https://github.com/talebook/talebook Talebook 是一个简洁但强大的私人书籍管理系统。它基于 Calibre 项目构建&#xff0c;具备书籍管理、在线阅读与推送、用户管理、SSO 登录、从百度/豆瓣拉取书籍信息等功能。 友情提醒&#x…

工业交换机外壳材质大比拼,看看哪种外壳适合你

在工业领域里&#xff0c;交换机就像我们的网络心脏&#xff0c;时刻跳动着确保信息畅通无阻。而它的外壳&#xff0c;就是保护这颗“心脏”的铠甲。今天&#xff0c;咱们就来聊聊这些铠甲——工业交换机外壳的材质和防护等级&#xff0c;看看它们如何守护我们的网络世界。 首…

网络编程基础回顾

计算机网络&#xff08;5&#xff09;&#xff1a;运输层 OSI 模型与 TCP/IP 协议 OSI七层协议模型 (open system interconnection) 应用层&#xff1a;为应用数据提供服务表示层&#xff1a;数据格式转化&#xff0c;数据加密会话层&#xff1a;建立、维护和管理会话传输层&…

算法设计与分析 动态规划/回溯

1.最大子段和 int a[N]; int maxn(int n) {int tempa[0];int ans0;ansmax(temp,ans);for(int i1;i<n;i){if(temp>0){tempa[i];}else tempa[i];ansmax(temp,ans);}return ans; } int main() {int n,ans0;cin>>n;for(int i0;i<n;i) cin>>a[i];ansmaxn(n);co…

【吃透Java手写】4-Tomcat-简易版

【吃透Java手写】Tomcat-简易版-源码解析 1 准备工作1.1 引入依赖1.2 创建一个Tomcat的启动类 2 线程池技术回顾2.1 线程池的使用流程2.2 线程池的参数2.2.1 任务队列&#xff08;workQueue&#xff09;2.2.2 线程工厂&#xff08;threadFactory&#xff09;2.2.3 拒绝策略&…

财务管理|基于SprinBoot+vue的财务管理系统(源码+数据库+文档)

财务管理系统 目录 基于SprinBootvue的财务管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 1管理员功能模块 2员工功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1…

视频批量剪辑指南:一键合并视频并添加背景音乐,高效便捷

在数字化时代&#xff0c;视频剪辑已经成为了一项常见且重要的技能。无论是制作家庭影片、工作展示还是社交媒体内容&#xff0c;掌握高效的视频剪辑技巧都能极大地提升我们的工作效率和创作质量。本文将为您介绍云炫AI智剪中高效的视频批量剪辑方法&#xff0c;让您能够一键合…

在线教程|图灵奖得主Yann LeCun盛赞!小红书开源InstantID,一张原图即可定制多种风格写真

不久前&#xff0c;一群来自小红书的 95 后工程师联合北大团队发布了开源项目「InstantID」&#xff0c;只需上传一张照片&#xff0c;这款 AI 写真神器就能轻松定制多种风格的 AI 写真&#xff0c;告别繁琐修图。 InstantID 一经发布就引起了广泛关注&#xff0c;GitHub 收藏量…

Java实现的网上书店系统(附带完整源码)

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者 实现技术:JSP技术;javaBean;servlet;MySql数据库。 系统功能结构图 该系统为MVC结构,它的运行环境分客户端、应用服务器端和数据库服务器端三部分 书店系统需求分析: 通过…

通用人工智能AGI,究竟是一个哲学问题还是技术问题?

引言 在探索人工智能的未来方向中&#xff0c;人工通用智能&#xff08;AGI&#xff09;的概念逐渐成为科技领域和哲学探讨的焦点。AGI旨在创建可以执行任何智能任务的机器&#xff0c;甚至在某些方面超越人类的能力。然而&#xff0c;关于AGI的研究不仅仅是技术问题&#xff…

天龙怀旧游戏python脚本

设置图&#xff1a; 游戏窗口最大化。 海贼洞这里定位你要回点的定位。 运行bat就行&#xff0c;脚本出错了还是会重新运行脚本&#xff0c;运行自动启动&#xff0c;end暂停脚本&#xff0c;home重新启动脚本 1. 我常用的是内挂回点脚本&#xff0c; 下面都是前台脚本&…