Java 网络通信编程(6):视频通话

在上期文章中,我们详细讲解了如何实现单张图片的传输技术。具体来说,我们通过以下步骤完成了图片传输:首先传输图片的尺寸信息,然后按顺序传输每个像素点的 RGB 值,接收端根据这些数据重建图片。

在掌握了单张图片传输的技术后,我们现在可以进一步探讨如何实现视频通信。视频通信的技术原理其实可以理解为:先将视频分解为连续的静态画面,按照一定的时间间隔传输这些画面,之后接收端按相同速率接收并播放这些画面。

1.调用摄像头

实现视频通信技术需要调用电脑摄像头,这需要我们使用外部 jar 包,这是它的下载地址:https://github.com/sarxos/webcam-capture 。由于本次导入的 jar 包较少,我们在项目结构中手动添加配置即可。

导入 jar 包后,我们便可以使用 Webcam,此处打开摄像头的操作非常简单。

java 复制代码
 Webcam webcam = Webcam.getDefault();
 webcam.open();

2.客户端线程

要实现图片连续传输,容易想到开启线程。在功能开发的初级阶段,我们仅需在原来传输图片的基础上套上线程框架。

java 复制代码
    class StatVideo extends Thread {
        public Graphics g;
        public OutputStream os;

        public StatVideo(Graphics g, OutputStream os) {
            this.g = g;
            this.os = os;
        }


        public void run() {
            Webcam webcam = Webcam.getDefault();
            webcam.open();
            while (true) {
                try {
                    Thread.sleep(100);

                    BufferedImage image = webcam.getImage();
                    g.drawImage(image, 10, 100, null);
                    int w = image.getWidth();
                    int h = image.getHeight();
                    System.out.println(w + " " + h);

                    //发送图片大小
                    writeInt(os, w);
                    writeInt(os, h);

                    //发送图片像素值
                    for (int y = 0; y < h; y++) {
                        for (int x = 0; x < w; x++) {
                            int rgb = image.getRGB(x, y);
                            writeInt(os, rgb);
                        }
                    }
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

其中 run 方法是核心逻辑,首先获取并打开默认摄像头,随后进入无限循环,每次循环先休眠 100 毫秒,接着获取摄像头的当前帧 BufferedImage 对象,通过 Graphics 对象将图片绘制,再调用 writeInt 方法将宽高每个像素的 RGB 值写入输出流。

3.服务端线程

同理,服务端也要开启线程来持续地接收图片信息并绘制图片。

java 复制代码
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        int w = readInt(is);
                        int h = readInt(is);

                        System.out.println("w = " + w + "  h = " + h);

                        //创建缓冲图片
                        BufferedImage bufferedImage = new BufferedImage(w, h,
                                BufferedImage.TYPE_INT_RGB);
                        //读取客户端发来的像素点
                        for (int i = 0; i < h; i++) {
                            for (int j = 0; j < w; j++) {
                                int rgb = readInt(is);
                                bufferedImage.setRGB(j, i, rgb);
                            }
                        }
                        g.drawImage(bufferedImage, 100, 100, null);

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }

        }).start();

此线程内部通过无限循环不断执行读取逻辑,首先调用 readInt 方法从输入流 is 中读取图片的宽度和高度并打印,接着根据读取到的宽高创建 TYPE_INT_RGB 类型的 BufferedImage 缓冲图片,随后读取客户端发送的像素 RGB 值,并通过 setRGB 方法将 RGB 值设置到缓冲图片对应坐标位置,最后利用 Graphics 对象 g 绘制还原后的缓冲图片。

4.优化方向

在加入线程后我们就实现了从单纯地图片传输到视频通信的技术进步。然而现在的视频通信仅仅是初级阶段,仍存在帧数较低、延迟较高、分辨率偏低等一系列问题,不能给客户很好的实时交互体验。后续我们会从从压缩数据、利用 UDP 协议等方向优化程序。

相关推荐
要开心吖ZSH6 小时前
一文搞懂:JDK 21 虚拟线程 vs N种异步方案,到底该怎么选?
java·数据库·jdk·虚拟线程
guodingdingh11 小时前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯12 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育13 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵13 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔14 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影15 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
一叶龙洲15 小时前
wslg打开Ubuntu24.04默认打开图形界面
linux·服务器·数据库·ubuntu
Miao1213116 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔16 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程