利用javacv制作的最简视频监控

原理,利用FFmpegFrameGrabber 采集到视频帧,再利用Java2DFrameConverter  把采集的frame转换为Image,再利用ImageIO把image转发到outputStream。

客户端利用ImageIO收到inputstream 就是image格式的数据,直接showimage()就可显示了

采集放在socket客户端,也可放在serversocket 服务器端

本例采集放在socket端 (只能使用不压缩图片格式:bmp)


import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.Socket;

public class Khd1 {
    public static void main(String[] args) throws IOException, InterruptedException {
        Socket socket=new Socket("192.168.43.187",3000);
        OutputStream outputStream=socket.getOutputStream();
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("/dev/video0");   //读摄像头
        grabber.start();
        Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
        while(true) {
            Frame frame = grabber.grabFrame();
            BufferedImage bufferedImage = java2DFrameConverter.getBufferedImage(frame);
            ImageIO.write(bufferedImage, "bmp", outputStream);   //bmp,png 验证,只能用这两种图片格式
        }
    }
}
显示播发服务器端:

import org.bytedeco.javacv.CanvasFrame;
import javax.imageio.ImageIO;
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(3000);
        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();
        CanvasFrame canvas = new CanvasFrame("播发");//新建一个预览窗口

        while(true) {
              Image image = ImageIO.read(inputStream);
              canvas.showImage(image);
        }
    }
}
下一步,利用前面写的利用公网ip,实现的点对点传输数据的程序,把上面程序加进去,做一个内网视频监控。

   后面一查网络,不得了,十几分钟传了几百G的流量。这个不是实用程序,只说明原理,真实的情况应该是加入各种数据压缩后才能网络传输。

-------------------------------------------------------------------------------------------------------------------------------

FFmpegFrameGrabber  FFmpegFrameRecorder   都可以从网络拉流和推流,采用stmp协议,问题是这俩只能做客户端,不能一个做客户端,一个做服务器组网。所以这两者要一个推流,一个做拉流,中间必须引入第三方stmp服务器,下面就是利用srs  stmp服务器,FFmpegFrameGrabber 做拉流,FFrameFrameRecoder 做推流的网络摄像头程序,注意采用stmp协议,必须采用flv 格式。


import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import java.io.*;


import static org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264;

public class Khd1 {
    public static void main(String[] args) throws IOException{
 
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("/dev/video0");   //读摄像头
        grabber.start();
        FFmpegFrameRecorder recorder=new FFmpegFrameRecorder("rtmp://127.0.0.1/live/livestream",200,150);
        recorder.setVideoCodec(AV_CODEC_ID_H264);
        recorder.setFormat("flv");
        recorder.start();

        while(true) {
            Frame frame = grabber.grabFrame();
            recorder.record(frame);
        }
    }
}

 


import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;


import java.io.*;
import static org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264;

public class Test {

    public static void main(String[] args) throws IOException{
        
               FFmpegFrameGrabber grabber=new FFmpegFrameGrabber("rtmp://127.0.0.1/live/livestream");
               grabber.setFormat("flv");
               grabber.setVideoCodec(AV_CODEC_ID_H264);
               grabber.start();
                CanvasFrame canvas = new CanvasFrame("播发");//新建一个预览窗口

                while(true) {
                    Frame frame=grabber.grab();
                    canvas.showImage(frame);
                }
            }
        }



=========================================================================不使用ffmpegframerecorder 推流方式,ffmpegframegrabber采集后生成frame视频帧,再生成图片,再压缩图片。客户端与服务器之间直接传递含有图片数据的字节数组。

改进后可以使用jpg格式压缩的程序,使用此方法,感觉视频显示延时很短,明显优于利用srs 服务器中转。但网络传输带宽要大些。采用这种方式,可省去中间stmp 服务器,直接编写点对点程序。如果带宽太小,可以在采集视频时把宽度,高度取小些,在生成图片时把图片帧也取小。

后期看能不能在图片之间加入时间戳,最后生成可全段查询回放的视频。

现在想想,完全可以抛开什么stmp协议,自己完全可以定义传输协议,比如规定传送几帧图片后就传送时间标志,或者隔几帧图片就传送一段声音数据,最后再根据时间合成图片流,声音流。甚至图片帧之间还可传输控制命令。现在知识储备不够,慢慢理解,学习,最后实现。

 


import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.Socket;

public class Khd1 {

        public static void main(String[] args) throws IOException, InterruptedException {
            Socket socket=new Socket("127.0.0.1",3000);
            OutputStream outputStream=socket.getOutputStream();
            ObjectOutputStream outputStream2=new ObjectOutputStream(outputStream);

            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("/dev/video0");   //读摄像头
            grabber.setImageWidth(720);
            grabber.setImageHeight(540);    //这两句严重影响带宽。
            grabber.start();
            Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();

            while(true) {
                Frame frame = grabber.grabFrame();
                BufferedImage bufferedImage = java2DFrameConverter.getBufferedImage(frame);
                ByteArrayOutputStream outputStream1=new ByteArrayOutputStream();
                ImageIO.write(bufferedImage, "jpg", outputStream1);   //支持bmp,png,jpg,前两种没压缩

                byte[] b=outputStream1.toByteArray();
                outputStream2.writeObject(b);
                outputStream2.flush();
                outputStream1=null;
                Thread.sleep(1000/20);           //图片帧率,这是大概数字,因为压缩还要占用时间
            }
        }
    }



import org.bytedeco.javacv.CanvasFrame;
import javax.imageio.ImageIO;
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ServerSocket serverSocket = new ServerSocket(3000);
        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();
        ObjectInputStream inputStream1=new ObjectInputStream(inputStream);

        CanvasFrame canvas = new CanvasFrame("播放");//新建一个预览窗口

        while(true) {
            byte[] b= (byte[]) inputStream1.readObject();
            ByteArrayInputStream inputStream2=new ByteArrayInputStream(b);
            Image image = ImageIO.read(inputStream2);
            canvas.showImage(image);
        }
    }
}

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(音视频,java,开发语言)