屏幕广播

 

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;
    }    
}

 

转载于:https://www.cnblogs.com/yihaifutai/p/6869641.html

1.屏幕广播 除了原来的全屏和窗口广播模式外,增加了绑定窗口模式。老师可以选择屏幕的某个部分广播给学生,以增加教学的直观性。 2.监控转播 监控时抓取快照。老师可以在监控学生的时候,对学生画面拍快照,保存学生画面的截图。 3.班级模型管理 新增加班级模型管理按钮,并设计了单独的管理界面,实现对班级模型的统一管理。 4.屏幕录制 屏幕录制经过全面技术革新,可以直接录制成 ASF 文件,也可以用 Windows 自带的 Media Player 直接播放。 屏幕录制的音视频不再分两个文件存放,保证了录制的文件的音视频同步性。 屏幕录制可以选择质量方案,以便客户在录制的文件尺寸和质量上,根据需要取舍。 屏幕录制提示小红点闪烁,录制过程更加直观。 提供屏幕录制转换器,以便早期的客户把老版本的文件转换为 ASF 文件。 5.远程设置 远程设置新增桌面主题设置,桌面背景设置,屏幕保护方案设置。 远程设置可以设置学生的频道号和音量。 远程设置可以设置学生的卸载密码,是否启用进程保护,断线锁屏,热键退出。 6.远程命令 新增可以远程关闭所有学生正在执行的应用程序。 7.分组管理 分组管理可以新建,删除,重命名分组。添加和删除分组中的成员。 分组信息随班级模型永久保存,下次上课可以直接使用保存的分组。 8.随堂小考 使用此功能,教师可以启动快速的单题考试或随堂调查,并立即给出结果。 9.系统日志 显示和自动保存系统运行过程中的关键事件,包括学生登录登出,电池电量,资源不足,提交文件等。 极域电子教室 注意事项 1.安装本产品前,如果已安装我公司以前的版本或同类软件,请先将以前版本或同类软件移除后,再进行安装。 2.安装本软件后,请一定要重新启动计算机才可使用。如果不重新启动计算机,有可能会造成本软件的某些功能不能正常使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值