UDP分包传输视频


一、Webcam的使用

下载地址
https://github.com/sarxos/webcam-capture?tab=readme-ov-file
可以使用maven或者手动导包的方式使用

窗口中使用webcam

	Webcam webcam = Webcam.getDefault();
	
	webcam.setViewSize(WebcamResolution.VGA.getSize());
	
	WebcamPanel panel = new WebcamPanel(webcam);
	panel.setFPSDisplayed(true);
	panel.setDisplayDebugInfo(true);
	panel.setImageSizeDisplayed(true);
	panel.setMirrored(true);
	
	JFrame window = new JFrame("Test webcam panel");
	window.add(panel);
	window.setResizable(true);
	window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	window.pack();

webcam获取图片

	BufferedImage image = webcam.getImage();

二、图片传输

方式:将BufferedImage转换为二维数组,将二维数组分片并进行传输

BufferedImage转换为二维数组

	int width = image.getWidth();
	int height =  image.getHeight();
	int[][] arr = new int[width][height];
	for (int i = 0; i < width; i++) {
		for (int j = 0; j < height; j++) {
			arr[i][j] = image.getRGB(i,j);
		}
	}

分包传输

分片传输:
udp传输数据有大小限制,最大为65507 ,根据UDP协议,从UDP数据包的包头可以看出,UDP的最大包长度是2^16 -1的个字节。由于UDP包头占8个字节,而在IP层进行封装后的IP包头占去20字节,所以这个是UDP数据包的最大理论长度是2^16 - 1 - 8 - 20 = 65507字节

图片大小640* 480 *4 超过upd最大包长度,因此需要分片传输,分片需要给数据包添加序号,接收端根据序号对接收到的数据报进行排序并还原成二维数组
先将图片的宽高发送给接收端,随后将每一列数据添加序号发送给接收端

	DatagramSocket s = new DatagramSocket();
	ByteArrayOutputStream bas = new ByteArrayOutputStream();
	DataOutputStream ds = new DataOutputStream(bas);
	//把宽高发送给接收端
	ds.writeInt(width);
	ds.writeInt(height);
	byte[] data = bas.toByteArray();
	DatagramPacket p = new DatagramPacket(data,data.length,address);
	s.send(p);
	for (int i = 0; i < width; i++) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream ();
		DataOutputStream dos = new DataOutputStream(baos);
		//包的序号
		dos.writeInt(i);
		System.out.println("序号为:"+i);
		//一列数据
		for (int j = 0; j < height; j++) {
			dos.writeInt(arr[i][j]);
		}
		dos.flush();
		byte[] imageData = baos.toByteArray();
		System.out.println(Arrays.toString(imageData));
		DatagramPacket dp = new DatagramPacket(imageData,imageData.length,address);
		s.send(dp);
		System.out.println("imageData.length="+imageData.length);
	}

数据包组装

     byte[] buffer = new byte[8];
     DatagramPacket p = new DatagramPacket(buffer, buffer.length);
     s.receive(p);
     ByteArrayInputStream bis = new ByteArrayInputStream(p.getData());
     DataInputStream dis = new DataInputStream(bis);
     int width = dis.readInt();
     int height = dis.readInt();
     System.out.println("width="+width+" height="+height);
     int[][] arr = new int[width][height];
     for (int i = 0; i < width; i++) {
         byte[] b = new byte[height * 4 + 4];
         DatagramPacket dp = new DatagramPacket(b, b.length);
         s.receive(dp);
         ByteArrayInputStream bs = new ByteArrayInputStream(dp.getData());
         DataInputStream ds = new DataInputStream(bs);
         int seque = ds.readInt();
//                                System.out.println("接收到的序号为:" + seque);
         if(seque < width){
             for (int j = 0; j < height; j++) {
                 arr[seque][j] = ds.readInt();
             }
         }

     }

二维数组转换成BufferedImage

    public static BufferedImage matrixToBufferedImage(int[][] matrix) {
        int type = BufferedImage.TYPE_INT_RGB;

        BufferedImage image = new BufferedImage(matrix.length, matrix[0].length, type);
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                image.setRGB(i,j,matrix[i][j]);
            }
        }
        return image;
    }

三、完整代码

WebcamPanelExample.java
发送方

package udp.webcamv2;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;

import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Arrays;


public class WebcamPanelExample {

	public static void main(String[] args) throws InterruptedException {

		Webcam webcam = Webcam.getDefault();

		webcam.setViewSize(WebcamResolution.VGA.getSize());

		WebcamPanel panel = new WebcamPanel(webcam);
		panel.setFPSDisplayed(true);
		panel.setDisplayDebugInfo(true);
		panel.setImageSizeDisplayed(true);
		panel.setMirrored(true);

		JFrame window = new JFrame("Test webcam panel");
		window.add(panel);
		window.setResizable(true);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.pack();
		InetSocketAddress address = new InetSocketAddress("127.0.0.1",1239);
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("webcam端线程执行啦!");
				while(true){
					try {
						BufferedImage image = webcam.getImage();
						if(image == null) continue;
						Thread.sleep(50);
						int width = image.getWidth();
						int height =  image.getHeight();
						int[][] arr = new int[width][height];
						for (int i = 0; i < width; i++) {
							for (int j = 0; j < height; j++) {
								arr[i][j] = image.getRGB(i,j);
							}
						}

						DatagramSocket s = new DatagramSocket();
						ByteArrayOutputStream bas = new ByteArrayOutputStream();
						DataOutputStream ds = new DataOutputStream(bas);
						//把宽高发送给接收端
						ds.writeInt(width);
						ds.writeInt(height);
						byte[] data = bas.toByteArray();
						DatagramPacket p = new DatagramPacket(data,data.length,address);
						s.send(p);
						for (int i = 0; i < width; i++) {
							ByteArrayOutputStream baos = new ByteArrayOutputStream ();
							DataOutputStream dos = new DataOutputStream(baos);
							//包的序号
							dos.writeInt(i);
							System.out.println("序号为:"+i);
							//一列数据
							for (int j = 0; j < height; j++) {
								dos.writeInt(arr[i][j]);
							}
							dos.flush();
							byte[] imageData = baos.toByteArray();
							System.out.println(Arrays.toString(imageData));
							DatagramPacket dp = new DatagramPacket(imageData,imageData.length,address);
							s.send(dp);
							System.out.println("imageData.length="+imageData.length);
						}

					} catch (IOException | InterruptedException e) {
						e.printStackTrace();
					}
			}
			}
		}).start();


		window.setVisible(true);
	}

}

Receiver.java
接收方


package udp.webcamv2;


import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;


public class Receiver extends JFrame {
    private String MY_IP = "127.0.0.1";
    private  int MY_PORT = 1239;


    public Receiver(){
        setSize(800,800);
        setLayout(new FlowLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
    public static void main(String[] args) {
        Receiver re = new Receiver();
        //接收图片并画在窗口展示出来
        try {
            InetSocketAddress address = new InetSocketAddress(re.MY_IP, re.MY_PORT);
            DatagramSocket s = new DatagramSocket(address);
            new Thread(new Runnable(){
                @Override
                public void run() {
                    while(true) {
                        try {
                            byte[] buffer = new byte[8];
                            DatagramPacket p = new DatagramPacket(buffer, buffer.length);
                            s.receive(p);
                            ByteArrayInputStream bis = new ByteArrayInputStream(p.getData());
                            DataInputStream dis = new DataInputStream(bis);
                            int width = dis.readInt();
                            int height = dis.readInt();
                            System.out.println("width="+width+" height="+height);
                            int[][] arr = new int[width][height];
                            for (int i = 0; i < width; i++) {
                                byte[] b = new byte[height * 4 + 4];
                                DatagramPacket dp = new DatagramPacket(b, b.length);
                                s.receive(dp);
                                ByteArrayInputStream bs = new ByteArrayInputStream(dp.getData());
                                DataInputStream ds = new DataInputStream(bs);
                                int seque = ds.readInt();
//                                System.out.println("接收到的序号为:" + seque);
                                if(seque < width){
                                    for (int j = 0; j < height; j++) {
                                        arr[seque][j] = ds.readInt();
                                    }
                                }

                            }

                            BufferedImage bi = matrixToBufferedImage(arr);
                            Graphics g = re.getGraphics();
                            g.drawImage(bi,0,0,re);

                        } catch (IOException exception) {
                            exception.printStackTrace();
                        }
                    }

                    }

            }).start();

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }

    public static BufferedImage matrixToBufferedImage(int[][] matrix) {
        int type = BufferedImage.TYPE_INT_RGB;

        BufferedImage image = new BufferedImage(matrix.length, matrix[0].length, type);
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                image.setRGB(i,j,matrix[i][j]);
            }
        }
        return image;
    }
}

三、实现效果

在这里插入图片描述


四、总结

本文介绍了利用upd传输视频的整体流程,代码目前还存在的问题是必须先启动接收方再启动发送方,否则数据会混乱,接收方无法正确展示图片。

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值