springboot如何实现视频播放-防止视频被盗取-视频加密解密

今日学习

关注博主,每天分享实战技术和优秀资源推荐(有好资源可以推荐给博主)。

博主一直做开源产品,目前已开源多款后台架构,开源地址:

https://gitee.com/msxy

H5-Video视频播放

<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.ogg" type="video/ogg">
</video>

详细参数使用说明:

<video
    controls
    autoplay
    loop
    preload="auto"
    poster="img/popup-img.png"
    webkit-playsinline="true"
    playsinline="true"
    x5-video-player-type="h5"
    x5-video-player-fullscreen="true"
    x-webkit-airplay="allow"
    x5-video-orientation="portraint"
    style="object-fit:fill">
        <source src="video.mp4" type="video/mp4">
        <source src="video.ogg" type="video/ogg; codecs=dirac, speex">
        <p>你的浏览器不支持 <code>video</code> 标签.</p>
</video>

如何防止视频连接被获取

正常模式下,在<source src="movie.mp4" type="video/mp4">中直接使用了视频的地址,比如:movie.mp4。这样通过查看源代码或者F12能很快的定位到视频的全路径地址,那么如何控制视频地址不对外展示呢?

前端编写似乎还,不要暴露mp4等视频地址,编写方式如下:

<source src="'+prefix+'/kclient/getVideo/'+id+'" type="video/mp4">


视频地址换成后台请求地址,请求后台根据传入的id查询出对应的视频信息,将视频信息通过response流的模式写出,代码如下:

@RequestMapping("/getVideo/{id}")
    public void getVideo(HttpServletRequest request,HttpServletResponse response,@PathVariable String id){
        //视频资源存储信息
        PageData pd = new PageData();
        pd.put("id",id);
        PageData filePd = sourceService.findVideoInfo(pd);
        response.reset();
        //获取从那个字节开始读取文件
        String rangeString = request.getHeader("Range");
        try {
            //获取响应的输出流
            OutputStream outputStream = response.getOutputStream();
            File file = new File(ParaUtil.localName+filePd.get("file_path").toString());
            if(file.exists()){
                RandomAccessFile targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                //播放
                if(rangeString != null){
                    long range = Long.valueOf(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
                    //设置内容类型
                    response.setHeader("Content-Type", "video/mp4");
                    //设置此次相应返回的数据长度
                    response.setHeader("Content-Length", String.valueOf(fileLength - range));
                    //设置此次相应返回的数据范围
                    response.setHeader("Content-Range", "bytes "+range+"-"+(fileLength-1)+"/"+fileLength);
                    //返回码需要为206,而不是200
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设定文件读取开始位置(以字节为单位)
                    targetFile.seek(range);
                }else {//下载
                    //设置响应头,把文件名字设置好
                    response.setHeader("Content-Disposition", "attachment; filename="+filePd.get("name"));
                    //设置文件长度
                    response.setHeader("Content-Length", String.valueOf(fileLength));
                    //解决编码问题
                    response.setHeader("Content-Type","application/octet-stream");
                }
                byte[] cache = new byte[1024 * 300];
                int flag;
                while ((flag = targetFile.read(cache))!=-1){
                    outputStream.write(cache, 0, flag);
                }
            }else {
                String message = "file:"+filePd.get("name")+" not exists";
                //解决编码问题
                response.setHeader("Content-Type","application/json");
                outputStream.write(message.getBytes(StandardCharsets.UTF_8));
            }
            outputStream.flush();
            outputStream.close();
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
        }
    }

视频意外流失,如何控制视频不被传播

在我们实际运营过程中,可能会存在视频被流失的风险,一旦视频流失可能会对企业造成很大的影响,那么如何避免视频被流出呢?

通过java对视频流进行加解密处理,及时视频外流,也无法对视频进行播放。

package com.qingfeng.util;
 
import java.io.*;
 
 
public class VideoEncodeUtil {
    public static void main(String[] args) throws Exception {
        encrypt("D:\\py交易\\11.mp4", "fuckyourself");
        decrypt("D:\\py交易\\11.mp4", "D:\\py交易\\22.mp4", 4);
        System.out.println(readFileLastByte("D:\\py交易\\11.mp4", 12));
    }
 
    /**
     * @title 文件file进行加密
     * @description 文件file进行加密
     * @author Administrator
     * @updateTime 2021/6/29 17:36
     */
    public static void encrypt(String fileUrl, String key)
        throws Exception {
        File file = new File(fileUrl);
        String path = file.getPath();
 
        if (!file.exists()) {
            return;
        }
 
        int index = path.lastIndexOf("\\");
        String destFile = path.substring(0, index) + "\\" + "abc";
        File dest = new File(destFile); //获取待加密文件的输入流
        InputStream in = new FileInputStream(fileUrl); //创建中转文件输出流
        OutputStream out = new FileOutputStream(destFile); //待加密文件的流
 
        byte[] buffer = new byte[1024];
        int r; //加密之后的文件的流
        byte[] buffer2 = new byte[1024];
 
        while ((r = in.read(buffer)) > 0) {
            for (int i = 0; i < r; i++) {
                byte b = buffer[i]; //buffer2[i]=b==255?0:++b;//每个字节加2加密
                b += 2;
                buffer2[i] = b;
            }
 
            out.write(buffer2, 0, r);
            out.flush();
        }
 
        in.close();
        out.close();
        file.delete();
        dest.renameTo(new File(fileUrl));
        appendMethodA(fileUrl, key);
        System.out.println("加密成功");
    }
 
    /**
     * @title appendMethodA
     * @description appendMethodA
     * @author Administrator
     * @updateTime 2021/6/29 17:42
     */
    public static void appendMethodA(String fileName, String content) {
        try { //打开一个随机访问文件流,按读写方式
 
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw"); //文件长度,字节数
            long fileLength = randomFile.length(); //将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.writeBytes(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * @title 解密
     * @description 解密
     * @author Administrator
     * @updateTime 2021/6/29 17:40
     */
    public static String decrypt(String fileUrl, String tempUrl, int keyLength)
        throws Exception {
        File file = new File(fileUrl);
 
        if (!file.exists()) {
            return null;
        }
 
        File dest = new File(tempUrl);
 
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
 
        //获取待解密的文件输入流
        InputStream is = new FileInputStream(fileUrl); //创建目标文件输出流,用来生成解密后的文件
        OutputStream out = new FileOutputStream(tempUrl);
        byte[] buffer = new byte[1024];
        byte[] buffer2 = new byte[1024];
        byte bMax = (byte) 255;
        long size = file.length() - keyLength;
        int mod = (int) (size % 1024);
        int div = (int) (size >> 10);
        int count = (mod == 0) ? div : (div + 1);
        int k = 1;
        int r;
 
        while (((k <= count) && ((r = is.read(buffer)) > 0))) {
            if ((mod != 0) && (k == count)) {
                r = mod;
            }
 
            for (int i = 0; i < r; i++) {
                byte b = buffer[i]; //buffer2[i]=b==0?bMax:--b;//每个字节减2解码
                b -= 2;
                buffer2[i] = b;
            }
 
            out.write(buffer2, 0, r);
            k++;
        }
 
        out.close();
        is.close();
 
        return tempUrl;
    }
 
    /*** 判断文件是否加密
    *@paramfileName
    *@return*
    * 加密成功返回key
    * 加密失败返回非key的字符串*/
    public static String readFileLastByte(String fileName, int keyLength) {
        File file = new File(fileName);
 
        if (!file.exists()) {
            return "没有文件";
        }
 
        StringBuffer str = new StringBuffer();
 
        try { //打开一个随机访问文件流,按读写方式
 
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw"); //文件长度,字节数
            long fileLength = randomFile.length(); //将写文件指针移到文件尾。
 
            for (int i = keyLength; i >= 1; i--) {
                randomFile.seek(fileLength - i);
                str.append((char) randomFile.read());
            }
 
            randomFile.close();
 
            return str.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        return "异常";
    }
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注