本系列文章想要实现利用UDP协议传输,从java程序获取的视频流以及音频流
github仓库源码地址:https://github.com/TStorms/JavacvUDPTest.git
上一篇:https://www.zpliu.top/archives/udp-javacv-1


一、实现UDP传输

现在来实现一个简单的原生UDP传输,后续可以使用Netty优化
udp传输很简单,一个接收,一个发送
接收方:

//1.创建DatagramSocket,建立接收服务,数字为监听端口。  
DatagramSocket ds = new DatagramSocket(10000);
//2.定义数据包。用于存储数据。  
byte[] buf = new byte[1024];  
DatagramPacket dp = new DatagramPacket(buf,buf.length);
while(true) //循环监听
{  
  //3,通过服务的receive方法将收到数据存入数据包中。  
  ds.receive(dp);//阻塞式方法。
  //4.获取数据      
  byte[] bytes = dp.getData();
  String data = new String(dp.getData(),0,dp.getLength());  
  System.out.println(data);  
}  
//5,关闭资源  
//ds.close();

发送方:

//1,创建udp服务。通过DatagramSocket对象。  
DatagramSocket ds = new DatagramSocket(8888);  
byte[] buf = new String("内容").getBytes();
 //2,将数据封装成数据包。指定IP,端口。
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.108"),10000);  
//3,将数据包发送出去。
ds.send(dp);  
//4,关闭资源。  
ds.close();

****这样就完成简单的发送了~~~


二、实现视频流传输

视频传输,你可以看成一帧就是一幅图像 一幅图像的传输
首先我们先把图像转换为byte[]数组

//转换器
Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
//转换成BufferedImage类
BufferedImage bufferedImage = java2DFrameConverter.convert(grabber.grab());
//BufferedImage转换成byte数组
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", bao);
byte[] bytes = bao.toByteArray();

因为udp 每次传输有大小限制(byte[].length < 1432),不能将一整幅图像传输过去
所以很蛋疼的,将一幅图像拆分成多次进行传输。

以下代码只是简单示例,并没有性能优化考虑,可能不能用于实际项目中~

//切割成每组1000
int array_length = (int) Math.ceil(bytes.length / 1000);
//告诉服务端开始传输一幅图像,大小是多少
mess = "start:" + array_length*1000;
starMess = mess.getBytes();
s.send(new DatagramPacket(starMess, starMess.length, hostAddress, UDPVideoServer.INPORT));
//开始切割发送
int from,to;
for (int i = 0; i < array_length ; i++){
    from = (int) (i * split_length);
    to = (int) (from + split_length);
    if ( to > bytes.length){
        to = bytes.length;
    }
    byte[] newByte = Arrays.copyOfRange(bytes, from, to);
    s.send(new DatagramPacket(newByte, newByte.length, hostAddress, UDPVideoServer.INPORT));
}
//发送完成
mess = "over";
starMess = mess.getBytes();
s.send(new DatagramPacket(starMess, starMess.length, hostAddress, UDPVideoServer.INPORT));

接收方就要拼接数组,合成图像

String mess = "";
int index = 0;
while (true) {
    socket.receive(dp);                            //接收信息
    mess = new String(dp.getData(), 0, dp.getLength());
    if (mess.contains("start")) {                 //判断方法教蠢~创建缓冲区
        bytes = new byte[Integer.parseInt(mess.split(":")[1])];
        index = 0;
    } else if (mess.equals("over")) {             //缓冲结束,显示图像
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        BufferedImage image = ImageIO.read(in);
        canvas.showImage(image);
    } else {                                      //写进缓冲区
        byte[] b = dp.getData();
        for (int a = 0; a < 1000; index++, a++) {
            bytes[index] = b[a];
        }
    }
}

具体完整代码在github:https://github.com/TStorms/JavacvUDPTest.git

****视频传输基本到这了!


三、音频流传输

音频流传输跟javacv无关,采用的是java原生的代码库

targetDataLine //用于声音采集

sourceDataLine //用于播放声音

简单代码实现播放传输
发送方:

AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100F, 16, 2, 4, 44100F, true);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
TargetDataLine targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
targetDataLine.open(audioFormat);
int nByte = 0;
final int bufSize=4*100;
byte[] buffer = new byte[bufSize];
targetDataLine.start();
while (nByte != -1) {
    nByte = targetDataLine.read(buffer, 0, bufSize);
    s.send(new DatagramPacket(buffer, bufSize, hostAddress, UDPAudioServer.INPORT));
}

接收方:

AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100F, 16, 2, 4, 44100F, true);
final SourceDataLine sourceDataLine;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
FloatControl fc=(FloatControl)sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
double value=2;
float dB = (float) (Math.log(value==0.0?0.0001:value)/Math.log(10.0)*20.0);
fc.setValue(dB);
final int bufSize=4*100;
byte[] buffer = new byte[bufSize];
while (true) {
    socket.receive(dp);
    sourceDataLine.write(dp.getData(), 0, bufSize);
}

音频传输就完成啦~

上一篇 下一篇