屏幕广播

Posted 艺海浮台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了屏幕广播相关的知识,希望对你有一定的参考价值。

 

1、服务器端

  1 public class ThreadMain {
  2 
  3     public static void main(String[] args) {
  4         new ServerSender().start();
  5     }
  6 
  7 }
  8 
  9 
 10 public class ServerSender {
 11     //UDP套接字
 12     private DatagramSocket socket;
 13     //创建机器人,抓图
 14     private Robot robot;
 15     private Rectangle rect;
 16     public ServerSender()  {
 17         try {
 18             socket=new DatagramSocket(8888);
 19             robot=new Robot();
 20             rect=new Rectangle(0, 0, 1366, 768);
 21         } catch (Exception e) {
 22             e.printStackTrace();
 23         }
 24     }
 25     public void start(){
 26         int i=0;
 27         while(true){
 28             sendOneScreen();
 29         }
 30     }
 31     private void sendOneScreen() {
 32         //1.抓取一屏幕
 33         byte[] frameData=catchOneScreen(true);
 34         //2.切割
 35         List<FrameUnit> units=splitScreen(frameData);
 36         //3.组装内容,并发送所有帧单元
 37         sendAllUnits(units);
 38     }
 39     //发送所有帧单元
 40     private void sendAllUnits(List<FrameUnit> units){
 41         for (FrameUnit unit:units) {
 42             //处理帧单元
 43             DatagramPacket pack=processUnit(unit);
 44             try {
 45                 socket.send(pack);
 46             } catch (IOException e) {
 47                 e.printStackTrace();
 48             }
 49         }
 50     }
 51     //处理帧单元
 52     private DatagramPacket processUnit(FrameUnit unit){
 53         byte[] buf=new byte[unit.getLength()+14];
 54         //时间戳
 55         byte[] timeBytes=bytesUtil.long2ByteArr(unit.getTimestamp());
 56         System.arraycopy(timeBytes, 0, buf, 0, 8);
 57         //count
 58         buf[8]=(byte) unit.getCount();
 59         //index
 60         buf[9]=(byte) unit.getIndex();
 61         //data长度
 62         byte[] unitLengBytes=bytesUtil.int2ByteArr(unit.getLength());
 63         System.arraycopy(unitLengBytes, 0, buf, 10, 4);
 64         //数据
 65         byte[] unitDataBytes=unit.getUnitData();
 66         System.arraycopy(unitDataBytes, 0, buf, 14, unitDataBytes.length);
 67         //设置数据报包的广播地址
 68         DatagramPacket pack=new DatagramPacket(buf, buf.length);
 69         InetSocketAddress addr=new InetSocketAddress("localhost", 9999);
 70         pack.setSocketAddress(addr);
 71         return pack;
 72         
 73     }
 74     //切屏
 75     private List<FrameUnit> splitScreen(byte[] frameData) {
 76         //frameUnit的长度
 77         int unitLength=60*1024;
 78         //帧单元集合
 79         List<FrameUnit> list = new ArrayList<>();
 80         int count=0;
 81         //正好整除unit大小
 82         if(frameData.length % unitLength==0){
 83             count=frameData.length / unitLength;
 84         }
 85         else{
 86             count=frameData.length / unitLength +1;
 87         }
 88         //取出时间戳
 89         long timestamp=System.currentTimeMillis();
 90         for(int i=0;i<count;i++){
 91             FrameUnit unit = new FrameUnit();
 92             unit.setTimestamp(timestamp);
 93             unit.setCount(count);
 94             unit.setIndex(i);
 95             //如果不是最后一帧单元,大小为60k;
 96             if(i !=(count-1)){
 97                 unit.setLength(60*1024);
 98                 byte[] unitData=new byte[60*1024];
 99                 System.arraycopy(frameData, i*60*1024, unitData, 0, 60*1024);
100                 unit.setUnitData(unitData);
101             }
102             //最后一帧处理
103             else{
104                 //取得最后一帧的长度
105                 int remain=frameData.length % unitLength==0?60*1024:frameData.length % unitLength;
106                 unit.setLength(remain);
107                 byte[] unitData=new byte[remain];
108                 System.arraycopy(frameData, i*60*1024, unitData, 0, remain);
109                 unit.setUnitData(unitData);
110             }
111             list.add(unit);
112         }
113     
114         return list;
115     }
116     //抓取一屏画面
117     private byte[] catchOneScreen(boolean zip) {
118         try {
119             BufferedImage image = robot.createScreenCapture(rect);
120             ByteArrayOutputStream bos = new ByteArrayOutputStream();
121             ImageIO.write(image, "jpg", bos);
122             //原生数据
123             byte[] rawrate=bos.toByteArray();
124             //需要压缩
125             if(zip){
126                 ByteArrayOutputStream bos0 = new ByteArrayOutputStream();
127                 ZipOutputStream zos=new ZipOutputStream(bos0);
128                 zos.putNextEntry(new ZipEntry("0001"));
129                 zos.write(rawrate);
130                 zos.close();
131                 bos0.close();
132                 //直接返回该数据,后面不再执行
133                 return bos0.toByteArray();
134             }
135             return rawrate;
136         } catch (Exception e) {
137             e.printStackTrace();
138         }
139         return null;
140     }
141 }

2、客户端

  1 public class StudentMain {
  2 
  3     public static void main(String[] args) {
  4         StudentUI ui = new StudentUI();
  5         new ReceiverThread(ui).start();
  6     }
  7 
  8 }
  9 
 10 public class ReceiverThread extends Thread {
 11     // 存放所有帧单元的集合
 12     private Map<Integer, FrameUnit> map = new HashMap<>();
 13     private StudentUI ui;
 14     private DatagramSocket socket;
 15 
 16     public ReceiverThread(StudentUI ui) {
 17         try {
 18             this.ui = ui;
 19             socket = new DatagramSocket(9999);
 20         } catch (SocketException e) {
 21             e.printStackTrace();
 22         }
 23     }
 24 
 25     public void run() {
 26         // 数据缓存区
 27         byte[] buf = new byte[60 * 1024 + 14];
 28         DatagramPacket pack = new DatagramPacket(buf, buf.length);
 29         try {
 30             while (true) {
 31                 socket.receive(pack);
 32                 // 解析数据报包成FrameUnit
 33                 FrameUnit unit = parsePack(pack);
 34                 // 处理帧单元
 35                 processUnit(unit);
 36             }
 37         } catch (IOException e) {
 38             e.printStackTrace();
 39         }
 40     }
 41 
 42     // 解析数据包,解析帧单元
 43     private FrameUnit parsePack(DatagramPacket pack) {
 44         // 缓冲区数据,含有header
 45         byte[] bufData = pack.getData();
 46         FrameUnit unit = new FrameUnit();
 47         // 处理时间戳
 48         long timestamp = bytesUtil.byte2long(bufData);
 49         unit.setTimestamp(timestamp);
 50         // frameUnit个数
 51         int count = bufData[8];
 52         unit.setCount(count);
 53         // frame索引
 54         int index = bufData[9];
 55         unit.setIndex(index);
 56         // 数据长度
 57         byte[] bytelength = new byte[4];
 58         System.arraycopy(bufData, 10, bytelength, 0, 4);
 59         int dataLen = bytesUtil.byte2int(bytelength);
 60         unit.setLength(dataLen);
 61         // 图像数据处理
 62         byte[] unitData = new byte[dataLen];
 63         System.arraycopy(bufData, 14, unitData, 0, dataLen);
 64         unit.setUnitData(unitData);
 65         return unit;
 66     }
 67 
 68     // 处理帧单元
 69     private void processUnit(FrameUnit unit) {
 70         // 如果集合为空,没有帧单元数据
 71         if (map.isEmpty()) {
 72             map.put(unit.getIndex(), unit);
 73         } else {
 74             // 提取map中存放的帧单元的时间戳
 75             long oldTime = map.values().iterator().next().getTimestamp();
 76             long currTime = unit.getTimestamp();
 77             // 同一帧
 78             if (oldTime == currTime) {
 79                 map.put(unit.getIndex(), unit);
 80             }
 81             // 新帧单元
 82             else if (currTime > oldTime) {
 83                 map.clear();
 84                 map.put(unit.getIndex(), unit);
 85             }
 86             // 老帧单元迟到,直接丢弃
 87             else {
 88             }
 89         }
 90         // 处理frame
 91         prcessFrame(true);
 92     }
 93 
 94     // 判断是否集齐了所有帧单元,处理称为一帧
 95     private void prcessFrame(boolean zip) {
 96         try {
 97             int count = map.values().iterator().next().getCount();
 98             int size = map.size();
 99             // 集齐了所有帧单元
100             if (count == size) {
101                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
102                 for (int i = 0; i < count; i++) {
103                     FrameUnit unit = map.get(i);
104                     bos.write(unit.getUnitData());
105                 }
106                 // 得到一屏幕画面的帧数据
107                 byte[] frameData = bos.toByteArray();
108                 if (zip) {
109                     ByteArrayOutputStream bos0 = new ByteArrayOutputStream();
110                     ByteArrayInputStream bis = new ByteArrayInputStream(frameData);
111                     ZipInputStream zis = new ZipInputStream(bis);
112                     zis.getNextEntry();
113                     byte[] buf = new byte[1024];
114                     int len = -1;
115                     while ((len=zis.read(buf)) != -1) {
116                         bos0.write(buf, 0, len);
117                     }
118                     zis.close();
119                     // 解压数据
120                     frameData = bos0.toByteArray();
121                 }
122                 ui.updateUI(frameData);
123                 map.clear();
124             }
125 
126         } catch (Exception e) {
127         }
128     }
129 
130 }
131 
132 
133 public class StudentUI extends JFrame{
134 
135     private static final long serialVersionUID = 2084514325030688532L;
136     //标签字段
137     private JLabel lbl;
138     public StudentUI(){
139         init();
140         this.setVisible(true);
141     }
142     private void init() {
143         this.setTitle("学生端");
144         this.setLayout(null);
145         this.setBounds(0, 0, 1366, 768);
146         
147         lbl=new JLabel();
148         lbl.setBounds(0, 0, 1366, 768);
149         this.add(lbl);
150         
151         this.addWindowListener(new WindowAdapter() {
152             @Override
153             public void windowClosing(WindowEvent e) {
154                 System.exit(-1);
155             }
156         });
157     }
158     //更新UI
159     public void updateUI(byte[] frameData){
160         try {
161             ByteArrayInputStream bis = new ByteArrayInputStream(frameData);
162             BufferedImage image = ImageIO.read(bis);
163             ImageIcon icon = new ImageIcon(image);
164             lbl.setIcon(icon);
165         } catch (Exception e) {
166         }
167     
168 }
169 }

3、工具类

public class bytesUtil {
    //字节数组转成int
    public static int byte2int(byte[] arr){
        int i0=arr[0] & 0xff;
        int i1=(arr[1] & 0xff)<<8;
        int i2=(arr[2] & 0xff)<<16;
        int i3=(arr[3] & 0xff)<<24;
        return i0 |i1|i2|i3;
    }
    //字节数组转成long
    public static long byte2long(byte[] arr){
        long i0=arr[0] & 0xffL;
        long i1=(arr[1] & 0xffL)<<8;
        long i2=(arr[2] & 0xffL)<<16;
        long i3=(arr[3] & 0xffL)<<24;
        long i4=(arr[4] & 0xffL)<<32;
        long i5=(arr[5] & 0xffL)<<40;
        long i6=(arr[6] & 0xffL)<<48;
        long i7=(arr[7] & 0xffL)<<56;
        return i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7;
    }
    /**
     * 将整数转换成字节数组
     */
    public static byte[] int2ByteArr(int i){
        byte[] bytes = new byte[4] ;
        bytes[0] = (byte)(i >> 0) ;
        bytes[1] = (byte)(i >> 8) ;
        bytes[2] = (byte)(i >> 16) ;
        bytes[3] = (byte)(i >> 24) ;
        return bytes ;
    }
    /**
     * 将长整数转换成字节数组
     */
    public static byte[] long2ByteArr(long i){
        byte[] bytes = new byte[8] ;
        bytes[0] = (byte)(i >> 0) ;
        bytes[1] = (byte)(i >> 8) ;
        bytes[2] = (byte)(i >> 16) ;
        bytes[3] = (byte)(i >> 24) ;
        bytes[4] = (byte)(i >> 32) ;
        bytes[5] = (byte)(i >> 40) ;
        bytes[6] = (byte)(i >> 48) ;
        bytes[7] = (byte)(i >> 56) ;
        return bytes ;
    }
}

public class FrameUnit {
    private long timestamp;
    private int count;
    private int index;
    private int length;
    private byte[] unitData;
    public long getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
    public byte[] getUnitData() {
        return unitData;
    }
    public void setUnitData(byte[] unitData) {
        this.unitData = unitData;
    }    
}

 

以上是关于屏幕广播的主要内容,如果未能解决你的问题,请参考以下文章

我无法通过广播将数据发送到活动中的片段

从广播接收器更新片段中的列表视图

如何使用警报管理器将数据从片段传递到广播接收器

支持动态或静态片段的不同屏幕尺寸?

片段布局不覆盖整个屏幕

处理屏幕旋转上的片段重复(带有示例代码)