模拟QQ软件的基于多线程的流媒体加密传输软件技术

模拟QQ软件的基于多线程的流媒体加密传输软件技术,第1张

模拟QQ软件的基于多线程的流媒体加密传输软件技术

模拟QQ软件,基于多线程编程捕捉摄像头及麦克风实时数据,基于socket通信设计发送端、接收端两个部分的,对音频和视频进行采集、加密或加水印、传输、解密或提取水印。同时基于数据库进行存储存储。

【先上效果图】



文章目录
  • 模拟QQ软件的基于多线程的流媒体加密传输软件技术
    • `【先上效果图】`
    • `【先上代码】`
  • 一、课题概述
    • 1.1 课题背景
    • 1.2 视频加密传输的意义
    • 1.3 本课设必备知识——TCP/IP
      • (1)TCP协议介绍
      • (2)TCP实现可靠性的机制
    • 1.3 本课设必备知识——socket
      • (1)socket介绍
      • (2)通信过程
  • 二、课题任务
    • 2.1 设计题目要求
    • 2.2 设计方案要求
    • 2.3 系统设计中的目标功能
    • 2.4 系统加密处理功能
      • (1)获取用于形成视频流的图像帧
      • (2)对发送端获取的图像帧进行加密传输
      • (3)对接收端获取的图像帧进行解密处理
  • 三、技术方案及关键问题
    • 3.1 开发平台选择
    • 3.2 系统开发流程
      • (1)视频采集
      • (2)视频加解密
      • (3)视频传输
      • (4)视频存储
      • (5)视频采集线程(发送端)
      • (6)视频加密传输线程(发送端)
      • (7)视频解密接收线程(接收端)
      • (8)视频播放与存储线程(接收端)
    • 3.3 需要解决的关键问题以及解决方法
      • (1)视频和音频的合成
      • (2)与数据库的连接
      • (3)视频的加密
      • (4)视频的传输和接收
      • (5)视频解密
  • 四、设计实现及测试
    • 4.1 系统成果展示
    • 4.2 系统各段代码功能介绍
  • 五、参考文献

【先上代码】
import sys
import time
import argparse
from socket import *
import threading
import pyaudio
import wave
import struct
import pickle
import numpy as np
import cv2
import pymysql
import os
import re
from moviepy.editor import VideoFileClip
from moviepy.editor import AudioFileClip
#---------------------------网络传输参数----------------------------------------
parser = argparse.ArgumentParser()

parser.add_argument('--host', type=str, default='127.0.0.1')
parser.add_argument('--port', type=int, default=10087)
parser.add_argument('--level', type=int, default=1)
parser.add_argument('-v', '--version', type=int, default=4)

args = parser.parse_args()

IP = args.host
PORT = args.port
VERSION = args.version
LEVEL = args.level
#---------------------------视频传输部分----------------------------------------
"""加密相关图片的读取"""
noise = cv2.imread("123.jpg")
key = np.array(noise,dtype = 'int')

"""音频地址"""
fg_audio_path = "wave.wav"
fg_video_path = "video.mp4"
"""接收端"""
class Video_Server(threading.Thread):
    def __init__(self, port, version) :
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.ADDR = ('', port)
        self.i = 1
        if version == 4:
            self.sock = socket(AF_INET ,SOCK_STREAM)
        else:
            self.sock = socket(AF_INET6 ,SOCK_STREAM)
    def __del__(self):
        self.sock.close()
        try:
            cv2.destroyAllWindows()
        except:
            pass
    def run(self):
        print("VIDEO server starts...")
        self.sock.bind(self.ADDR)
        self.sock.listen(1)
        conn, addr = self.sock.accept()
        print("remote VIDEO client success connected...")
        data = "".encode("utf-8")
        payload_size = struct.calcsize("L")		# 结果为4
        cv2.namedWindow('VIDEO', cv2.WINDOW_NORMAL)
        videoWriter = cv2.VideoWriter(fg_video_path, cv2.VideoWriter_fourcc('M','P','E','G'),10,(640,480))
        while True:
            while len(data) < payload_size:
                data += conn.recv(81920)
            packed_size = data[:payload_size]
            data = data[payload_size:]
            msg_size = struct.unpack("L", packed_size)[0]
            while len(data) < msg_size:
                data += conn.recv(81920)
            frame_data = data[:msg_size]
            data = data[msg_size:]
            frame = pickle.loads(frame_data)
            #if self.i >= 34:
            videoWriter.write(frame)
            #else:
            
            """解密"""

            frame = np.array(frame,dtype='int')
            frame = np.bitwise_xor(frame,key)
            
            """显示视频"""
            frame = np.array(frame,'uint8')
            self.i = self.i+1
            cv2.imshow('VIDEO', frame)
            if cv2.waitKey(1) & 0xFF == 27:
                videoWriter.release()
                break

"""发送端"""
class Video_Client(threading.Thread):
    def __init__(self ,ip, port, level, version):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.ADDR = (ip, port)
        if level <= 3:
            self.interval = level
        else:
            self.interval = 3
        self.fx = 1 / (self.interval + 1)
        if self.fx < 0.3:	# 限制最大帧间隔为3帧
            self.fx = 0.3
        if version == 4:
            self.sock = socket(AF_INET, SOCK_STREAM)
        else:
            self.sock = socket(AF_INET6, SOCK_STREAM)
        self.cap = cv2.VideoCapture(0)
    def __del__(self) :
        self.sock.close()
        self.cap.release()
    def run(self):
        print("VIDEO client starts...")
        while True:
            try:
                self.sock.connect(self.ADDR)
                break
            except:
                time.sleep(3)
                continue
        print("VIDEO client connected...")
        fps = 30
        size = (int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
        while self.cap.isOpened():
            ret, frame = self.cap.read()
            frame = np.bitwise_xor(frame,key)
            frame = np.array(frame,'uint8')
            data = pickle.dumps(frame)
            try:
                self.sock.sendall(struct.pack("L", len(data)) + data)
            except:
                break
            for i in range(self.interval):
                self.cap.read()

#---------------------------音频传输部分----------------------------------------
"""音频参数声明"""
CHUNK = 1024
FORMAT = pyaudio.paInt16    # 格式
CHANNELS = 2    # 输入/输出通道数
RATE = 44100    # 音频数据的采样频率
RECORD_SECONDS = 0.5    # 记录秒
p = pyaudio.PyAudio()

"""接收端"""
class Audio_Server(threading.Thread):
    def __init__(self, port, version) :
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.ADDR = ('', port)
        if version == 4:
            self.sock = socket(AF_INET ,SOCK_STREAM)
        else:
            self.sock = socket(AF_INET6 ,SOCK_STREAM)
        self.p = pyaudio.PyAudio()  # 实例化PyAudio,并于下面设置portaudio参数
        self.stream = None
    def __del__(self):
        self.sock.close()   # 关闭套接字
        if self.stream is not None:
            self.stream.stop_stream()   # 暂停播放 / 录制
            self.stream.close()     # 终止流
        self.p.terminate()      # 终止会话
    def run(self):
        print("Video server starts...")
        self.sock.bind(self.ADDR)
        self.sock.listen(1)
        conn, addr = self.sock.accept()
        print("remote Video client success connected...")
        data = "".encode("utf-8")
        payload_size = struct.calcsize("L")     # 返回对应于格式字符串fmt的结构,L为4
        self.stream = self.p.open(format=FORMAT,
                                  channels=CHANNELS,
                                  rate=RATE,
                                  output=True,
                                  frames_per_buffer = CHUNK
                                  )

        wf = wave.open(fg_audio_path,'wb')
        wf.setnchannels(CHANNELS)
        wf.setsampwidth(p.get_sample_size(FORMAT))
        wf.setframerate(RATE)
            
        while True:
            while len(data) < payload_size:
                data += conn.recv(81920)
            packed_size = data[:payload_size]
            data = data[payload_size:]
            msg_size = struct.unpack("L", packed_size)[0]
            while len(data) < msg_size:
                data += conn.recv(81920)
            frame_data = data[:msg_size]
            data = data[msg_size:]
            frames = pickle.loads(frame_data)
            wf.writeframes(b''.join(frames))
            for frame in frames:
                self.stream.write(frame, CHUNK)
            cv2.imshow("AUDIO",noise)
            if cv2.waitKey(1) & 0xFF == 27:
                wf.close()
                break

"""发送端"""
class Audio_Client(threading.Thread):
    def __init__(self ,ip, port, version):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.ADDR = (ip, port)
        if version == 4:
            self.sock = socket(AF_INET, SOCK_STREAM)
        else:
            self.sock = socket(AF_INET6, SOCK_STREAM)
        self.p = pyaudio.PyAudio()
        self.stream = None
        print("AUDIO client starts...")
    def __del__(self) :
        self.sock.close()
        if self.stream is not None:
            self.stream.stop_stream()
            self.stream.close()
        self.p.terminate()
    def run(self):
        while True:
            try:
                self.sock.connect(self.ADDR)
                break
            except:
                time.sleep(3)
                continue
        print("AUDIO client connected...")
        self.stream = self.p.open(format=FORMAT, 
                             channels=CHANNELS,
                             rate=RATE,
                             input=True,
                             frames_per_buffer=CHUNK)
        while self.stream.is_active():
            frames = []
            for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
                data = self.stream.read(CHUNK)
                frames.append(data)
            senddata = pickle.dumps(frames)
            try:
                self.sock.sendall(struct.pack("L", len(senddata)) + senddata)
            except:
                break
#---------------------------------主函数---------------------------------------
if __name__ == '__main__':
    vclient = Video_Client(IP, PORT, LEVEL, VERSION)
    vserver = Video_Server(PORT, VERSION)
    aclient = Audio_Client(IP, PORT+1, VERSION)
    aserver = Audio_Server(PORT+1, VERSION)
    vclient.start()
    aclient.start()
    time.sleep(1)    # make delay to start server
    vserver.start()
    aserver.start()
    while True:
        time.sleep(1)
        if not vserver.is_alive() or not vclient.is_alive():
            print("Video connection lost...")
        if not aserver.is_alive() or not aclient.is_alive():
            print("Audio connection lost...")
        if not aserver.is_alive() and not aclient.is_alive():
            video = VideoFileClip(fg_video_path)
            audio = AudioFileClip(fg_audio_path)
            videoclip2 = video.set_audio(audio)
            name1 = fg_video_path.split('.', 1)[0] + "_out.mp4"
            videoclip2.write_videofile(name1)
            try:
                db = pymysql.connect(host='localhost', user='root', passwd='123456', db='mysql')
                db.autocommit(True)
                cursor=db.cursor()
                '''创建表'''
                sql=""" create table if not exists path(id int,p varchar(100)) engine=innodb charset utf8"""
                cursor.execute(sql)
                i=1
                cursor.execute("truncate table path")
                for path,dirpath ,file in os.walk(r"D:91211176"):
                    for f in file:
                        r1=r'(video_out.mp4)'
                        if re.findall(r1,f):
                            path=path.replace("\","||")
                            insert="insert into path(id,p) values({},'{}')".format(i,path+"||"+f)
                            cursor.execute(insert)
                            i+=1
                cursor.execute("select * from path")
                db.commit()
                rows=cursor.fetchall()
                for r in rows:
                    print(r)
                print("complete!!!!")
            except:
                print("连接失败")
            sys.exit(0)


一、课题概述 1.1 课题背景

随着视频监控系统的广泛应用,小到一栋大楼、一个园区,大到一个城市都部署了大量的视频监控系统,对于视频数据的安全问题也日益凸显,如何有效保障视频采集端到服务端的视频数据的保密性也是视频采集监控系统刻不容缓需要解决的问题。本方案旨在通过密码技术,特别是国产密码算法技术,解决视频采集端与服务端的视频数据的安全。

视频加密是为了让要保护的视频不能轻易被下载,即使下载到了也是加密后的内容,其它人解开加密后的内容需要付出非常大的代价。

主要是因为现在的科技越来越发达,不法分子可以利用高科技手段直接获取视频内容,一旦出现这种情况,企业的损失将会变得非常大。要知道很多视频都是企业的机密内容,尤其是一些生产工艺,如果被竞争对手得到企业生产工艺,将会给企业造成严重打击。所以视频传输必须要加密,这样才能避免企业机密内容丢失,才能保障企业的利益。

1.2 视频加密传输的意义

我们的电脑中总会有一些隐私的视频,为了保证视频文件的安全,使用视频加密软件是很有必要的。视频加密软件加密强度高、支持格式广、加密速度快、 *** 作简单方便、安全稳定等等优点,视频加密软件不仅是为了保护隐私,有时候也是为了保护别人的劳动成果以及知识产权。

有时候电脑上的某一些视频需要保密,所以要视频加密软件,来保证视频文件的安全,一般这些视频加密软件具有加密强度高、支持格式多,加密后能够有效防止他人翻录提取以及破解。

加强视频传输的安全性,将视频进行加密,并且只能使用专用的视频加密播放器,其他外部人员获取加密视频也无法播放,针对加密视频进行高强度加密。同时,极大程度上阻止了那些有意翻录视频、拷贝教学视频的人,有效做到视频防翻录防复制,提高视频的安全性。

防止视频翻录,视频加密的一大作用是为了防止视频翻录,因为视频加密后,如果没有一个好的防翻录机制,也是没用的,被人很容易就把你的视频翻录走,从而导致培训机构受到一定损失。如果想要有效避免这类事情的发生,可以选择好的视频加密软件,其视频防翻录机制,可以保障了视频安全。

1.3 本课设必备知识——TCP/IP (1)TCP协议介绍

TCP(Transmission Control Protocol,传输控制协议):一种面向连接的、可靠的、基于字节流的传输层通信协议。从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族。不同于ISO模型的七个分层,TCP/IP协议参考模型把所有的TCP/IP系列协议归类到四个抽象层中。

每一层名字协议名称:

应用层: TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

传输层: TCP,UDP

网络层: IP,ICMP,OSPF,EIGRP,IGMP

数据链路层: SLIP,CSLIP,PPP,MTU

*图1.1 TCP/IP体系结构中常用的相互关系*

(2)TCP实现可靠性的机制

l 以通信双方之间建立连接

l TCP把数据流分割为适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。

l TCP为了保证不发生丢包,就给每个报文段一个序号,同时序号也保证了接收端的按序接收。TCP报文段的到达也可能会失序,如有必要,TCP将对收到的报文段进行重新排序,将收到的数据以正确的顺序交给应用层

l 接收端对已成功收到的包发回一个相应的确认(ACK);如果发送端在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。

l TCP用校验和函数来检验报文段是否有错误,在发送和接收时都要计算校验和,接收端若发现校验和有差错,将丢弃这个报文段和不确认收到此报文段。

l TCP还能提供流量控制:缓冲区(发送缓冲区、接收缓冲区)和滑动窗口

l 在拥塞控制上,采用慢启动和拥塞避免算法

*图1.2 TCP/IP体系结构中常用的相互关系*

1.3 本课设必备知识——socket (1)socket介绍

socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的:

*图1.3 socket通信流程*

服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket:

l 服务器为socket绑定ip地址和端口号

l 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开

l 客户端创建socket,客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket

l 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端

l 客户端连接成功,向服务器发送连接状态信息

l 服务器accept方法返回,连接成功

l 服务器端和客户端分别建立输入输出流,进行数据交流

l 客户端关闭,服务器端关闭

(2)通信过程

TCP协议通讯是严格的区分客户端以及服务端的,我们要通信必须由客户端主动去联系服务器端,而服务器端是不可以主动的请求连接客户端的,并且在客户端请求服务端之前,服务端需要事先启动服务监听端口,等待客户端的连接。

在JDK里面内置了两个类来实现TCP通讯,其中一个是ServerSocket类,用于服务器端,另一个是Socket,用于客户端。首先我们要创建代表了服务器端的ServerSocket对象,创建完成后相当于在本机开启了一个服务,并监听端口来等待客户端连接。然后创建代表客户端的Socket对象用于向服务器端发送请求,当服务器接收到请求后就可以响应并与客户端建立连接,就可以开始相互通信了。

二、课题任务

描述课题的任务,即课题研究开发的具体内容,含要实现的功能以及要达到的技术指标和经济指标。(1到2页纸,可以加二级标题,2.1 xxx 2.2 xxx 等等)

2.1 设计题目要求

基本要求:综合数据库和通信网知识完成音频/视频信息的传输和存储功能。

要求:题目一为必做题,完成本门课程即可通过,总分80分以下。

题目二和三均为附加选做题,有能力的同学可选择加做其中一道题,完成题目二总分80-90分,完成题目三总分90分以上。

*图2.1 信息系统软件设计流程图*

模拟QQ软件,基于多线程编程技术捕捉笔记本摄像头或麦克风实时数据,基于socket通信设计发送端、接收端两个部分,编程语言和工具不限,工程名必须包含学号,否则无效!

题目一,音/视频传输软件:完成音频或视频(二选一)的采集、传输、存储(必须基于数据库)

题目二,音/视频加密传输软件:完成音频或视频(二选一)的采集、简单的加密或加水印、传输、解密或提取水印、存储(必须基于数据库)

题目三,流媒体加密传输软件:完成音频和视频(二者皆有)的采集、加密或加水印、传输、解密或提取水印、存储(必须基于数据库)

2.2 设计方案要求

① Sender代码必须要在一台有摄像头的电脑上运行起来。然后把数据编码,压缩之后,再传给另外一个电脑。

② Reciever作为接受端,没什么特别的要求。

③ 两个电脑都必须要按转好numpy + opencv

④ 接受端关闭 *** 作是(输入键盘中的 Esc)退出监控,发送端是关闭不了这个监控的

⑤ 设置相关的IP地址

2.3 系统设计中的目标功能

① 通过电脑摄像头采集视频和音频,合成后保存在本地。

② 本地视频需要完成加密或者加水印的 *** 作,保护视频信息,如我采用了aes对称加密。

③ 通过数据库技术和socket通信,完成视频的发送记录存储和视频的传输,分为Server和Client端进行发和收。

④ 在接收视频后,能够无错误地将视频解密,还原回原来的视频。

2.4 系统加密处理功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdEjP4Ho-1650871741603)(file:///C:\Users\ZHAOHA~1\AppData\Local\Temp\ksohtml31116\wps34.png)]

*图2.2 系统设计中的目标功能拆解*

(1)获取用于形成视频流的图像帧

l 当所述图像帧满足预设的加密条件时,采用预设的加密算法对其进行加密;

在封装所述图像帧的过程中写入相应的加密标识信息,并将封装后的数据包发送给图像帧接收端;

l 所述预设的加密条件包括:所述图像帧按照预设方式承载加密指示信息。

所述图像帧按照预设方式承载加密指示信息包括:所述图像帧在预设位置的像素点值与预设值一致;

l 预设位置包括图像帧的4个顶点,所述预设值包括0xFFFF;

l 在图像帧发送端实施,所述图像帧包括桌面图像帧;

(2)对发送端获取的图像帧进行加密传输

l 图像帧获取单元,用于获取用于形成视频流的图像帧;

l 筛选加密单元,用于当所述图像帧满足预设的加密条件时,采用预设的加密算法对其进行加密;

l 封装发送单元,用于在封装所述图像帧的过程中写入相应的加密标识信息,并将封装后的数据包发送给图像帧接收端;

l 所述装置部署于桌面应用的图像帧发送端,所述图像帧获取单元获取的图像帧包括桌面图像帧;

(3)对接收端获取的图像帧进行解密处理

l 对接收到的视频流中的数据包进行解封装,获取图像帧;

l 根据数据包封装信息中携带的加密标识信息判断所述图像帧是否被加密;

l 采用相应的解密算法对所述图像帧进行解密;

l 根据数据包封装信息中携带的加密标识信息判断所述图像帧是否被加密包括:根据用于封装所述图像帧的RTP扩展头中携带的加密标识信息,执行所述判断;

l 在完成所述加密判断 *** 作及必要的解密 *** 作后,得到的图像帧为进行视频编码处理后的编码后图像帧;

l 采用与图像帧发送端所采用的视频编码方法对应的解码方法,对所述编码后图像帧进行解码,得到图像帧;

三、技术方案及关键问题 3.1 开发平台选择

l 使用语言:Python3

l 使用工具:opencv视频监控 + socket数据传输技术

现主流高级编程语言均可选用,但考虑到课题对程序性能要求不高,故采用Python语言可节省大量时间精力,且程序结构清晰易读。

在图形界面开发方面,相较C语言的MFC,采用Python的Tkinter库能十分便利地进行布局管理,无需进行大量配置。

算法实现上,一些加密算法有现成的库,而Python的库安装与环境配置比C语言方便许多。

综上,选用Python语言较为妥当。

3.2 系统开发流程 (1)视频采集

选用OpenCV库,可方便调用摄像头进行视频采集,得到图像原始数据。采集和后续步骤采用多线程并行,线程间通过一个队列来交互数据与缓冲。

l 采用多线程的方式开始录制图像画面并录制声音;

l 使用opencv调用电脑的摄像头,循环采集图像帧;

l 使用pyaudio打开麦克风进行录音;

l 使用opencv中函数,将加密视频文件、解密视频文件、保存为mp4文件

l 使用wave模块将音频数据保存至wav文件;

l 用ffmpeg将音频和视频合成为一个视频;

l 使用os库中的文件读写函数保存视频到本地。

(2)视频加解密

选用Crypto库,可从其中导入ARC4加密算法,对字符串数据进行加密。在此之前,需要将二维的图像矩阵转化为一维字符串,因此需要采用NumPy库进行转化。


(http://www.kaotop.com/file/tupian/20220429/0fe3cd378f414b4f809f872564ab8588.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAemhhb2hhb2JpbmdTVUk=,size_17,color_FFFFFF,t_70,g_se,x_16)

*图3.1 ARC4算法原理*

(3)视频传输

为保证通信实时性和流畅度,宜采用UDP协议传输。TCP协议中的反复握手机制大大降低了通信效率,数据出错时,重发机制则会进一步加剧延迟,在数据精确性要求不高、实时性要求高的图像传输背景下收益甚微,因此不宜采用。

同时,为了避免拥塞和减小重发代价,对原图像矩阵采取分段处理,接收端在接收到一帧的所有段后进行拼接。为了减小通信压力,对原图像进行JPEG压缩。

发送方向为ClientServer,因为只有使用了一台电脑,IP地址选择为本机地址127.0.0.1,使用socket通信以字节的方式发送。

*图3.2 UDP首部8个字节*

(4)视频存储

使用socket,监听本地端口,设置合适的套接字大小。若直接将视频帧存入数据库,则在读写效率低下,因此在数据库中存储视频文件的路径较为合适。视频文件由帧的生成,可由OpenCV库完成。

*图3.3 字节流套接字(SOCK_STREAM)*

(5)视频采集线程(发送端)

为方便流程控制,将图像的采集置于主线程。调用queue库,创建一个全局队列qs,并将长度限制在15左右,避免后续处理堵塞导致数据溢出。通过OpenCV的VideoCapture对象采集到的一帧,一方面用于更新图形界面上的图像展示,另一方面插入到队列qs中,供加密线程取用。对这个过程进行循环,并用绑定图形界面按钮的终止标志变量控制即可。

(6)视频加密传输线程(发送端)

在程序开端开启该线程,循环读取队列qs,当其非空时取出一帧进行 *** 作。先对帧进行压缩,调用OpenCV的imencode函数即可。然后将压缩后的帧利用NumPy转化为array类型,并调用tostring方法转化为字符串。将字符串送入ARC4算法加密后,得到加密字符串。最后,通过UDP协议发送到接收端IP的某个端口,即可完成一次传输。UDP的缓冲区小于图片大小,自动完成数据分段。当一张图片发送完,在末尾添加一个帧结束符例如‘imageend’。

(7)视频解密接收线程(接收端)

在程序开端开启该线程,循环接收来自发送端的数据,并后缀到一个缓冲字符串,直到接收到帧结束符。将该缓冲字符串送入ARC4解密函数,填入事先与发送端约定好的密钥,即可得到原字符串。再通过反过程,即数值化、重构矩阵,即可还原图像,并插入本地全局队列qr。

连接数据库,使用pymysql库创建在数据库中创建一个新表,再插入一条记录到表中;再使用aes加密对本地视频进行加密,存储加密后的视频。对称加密算法有加密速度非常快的优点,所以使用aes来加密。

*图3.4 AES加解密流程图*

(8)视频播放与存储线程(接收端)

该线程循环读取队列qr,非空时取帧,一方面用于更新图形界面上的图像展示,另一方面通过OpenCV的VideoWriter写入视频文件。当通信关闭时,结束视频写入,生成mp4文件,并将其路径写入MySQL表中。

*图3.5 创建一个数据库*

3.3 需要解决的关键问题以及解决方法 (1)视频和音频的合成

​ 问题:如果只是简单的开始摄像头录制视频,得到的视频是没有声音的,这样完成的是题目一,但我们想要得到的是视频和音频二者皆有。

解决:如果想得到完整的视频,需要另外采集音频,并将两者合成。

​ 解决方法是使用两个线程,分别保存视频和音频,最后使用FFmpeg函数将两者合在一起,得到含有声音的视频。

(2)与数据库的连接

​ 问题:在数据库中存储视频文件是一件不太现实的事情,尽管存储一些很小的视频是可能的。但经过我的实践,即使存储几M的视频,在读取时也会让数据库的不停跳出大量乱码,引起错误。如果是更大的视频,可能直接让数据库崩溃。

​ 解决:在数据库中只存放一条记录,将当前的视频记录在数据库中,减少数据库的存储量,同时也能记录视频信息。

(3)视频的加密

​ 问题:视频加密时,如果整个视频流进行加密,显然计算量会很大,并且随着拍摄的时间变长计算量会更巨大,很难保证视频的实时传输和加解密的内存控制。如果逐帧加密视频,还需要将视频分解,也将使整个过程变得很复杂。

​ 解决:选择性加密,仅加密头信息。该算法的原理是对这些头信息数据加密,将其变成随机序列,再与其它数据混合,使接收方在不知道密钥的情况下难以区分结构信息数据和视频信息数据,更难以知道数据结构和数据的具体内容,难以按原数据结构解码接收到的视频编码数据,无法获得原图像,达到加密目的 。

​ 具体到aes加密时, *** 作是这样的:加密时以byte[]的形式读取视频文件开头的一小段数据,一般256byte就足够了,然后对这个byte[]进行AES加密,把得到的密文替换到视频文件开头的256byte。因为视频文件的头被加密了,所以播放器是无法进行解码的,导致了文件无法被播放。因为视频文件中的相关媒体信息就保存在头里,头被加密了,也就无法对视频文件进行其它相关 *** 作(如获取媒体长度,提取某一位置的视频帧,视频截取等所有相关 *** 作)。

(4)视频的传输和接收

​ 这一部分因为学习过了《通信网基础》,问题不大。在Client端写好套接字,确定地址和端口,建立connect;在Serve端也初始化socket,使用bind进行端口绑定,对端口进行监听,完成这些等待Client端的连接。如果Client启动了连接,并且连接成功,这时客户端和服务器的连接就建立了,就可以开始发送数据。

(5)视频解密

​ 问题:解密视频时如何做,解密的密钥如何得到。

解决:解密视频时,调用AES解密算法,把被加密的256byte解密出来,替换回去,视频文件就可以正常解码,可以正常播放了。解密的密钥没有再单独发送,需要直接事先约定好密钥,这是为了整个过程的简单起见。最好的方法是将密钥附带着发送给接收方,此时一般采用其他的加密算法加密密钥、发送密钥。

四、设计实现及测试 4.1 系统成果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mWiXrVQC-1650871741607)(file:///C:\Users\ZHAOHA~1\AppData\Local\Temp\ksohtml31116\wps40.jpg)]

*图4.1 工作环境文件展示*

*图4.2 程序运行效果图*

*图4.3 程序保存加密的视频+音频*

*图4.4 加密的噪声图像*

*图4.5 图像加密效果图*

*图4.6 图像解密效果图*

*图4.5 音频提取效果图*

*图4.6 数据库保存效果图*

4.2 系统各段代码功能介绍

*图4.7 python调用程序所需的包*

*图4.8 网络传输参数设置*

使用FFmprg合成视频和音频,FFmpeg函数的使用方法在网上很容易找到,使用时可能会因为pycharm中版本太低报错,可以到官网下载,参考之前给出的下载教程。

*图4.9 连接情况*

视频录制使用“while True”进行死循环,不断调用摄像头,拍摄一张一张的图片,就形成了连续的视频,cv.imshow()用于显示摄像头,cv.waitKey(1)这个函数中,如果为数字1,表示一秒钟后结束程序,但由于是死循环,结束后就马上开启,就拍摄了连续的图像。

*图4.10 视频传输部分*

音频的读取是调用pyaudio库直接通过麦克风录制声音,可以获得.wav文件,在设备上打开一个数据流,就可以建立一个pyaudio.stream用来录音或者播放。

*图4.11 音频传输部分*

*图4. 文件格式及大小判断*

在pycharm中连接数据库,建表;pymysql.connect用于建立数据库的连接,需要给出数据库和密码;再获取游标,用于执行数据库的 *** 作,这里每次都会插入一条记录到表中;最后使用cursor.close()关闭连接。

*图4.12 连接mysql数据库*

采用了图像的点运算,也可以用面向对象的的写法,直接把密钥写在了类中,改进的话可以把密钥作为参数传进去。

*图4.13 发送端加密 *** 作*

实际的AES加密有AES-128、AES-192、AES-256三种,分别对应密钥长度为16字节,24字节,32字节,这里使用默认的AES-128。所以先将密钥转为16字节格式,相当于进行了填充,因为AES加密对加密文本有长度要求,必须是密钥字节数的倍数。

加密使用了ECB模式,aes加密中最简单也最常用的一种方式,也可以自己改成CBC模式,也很常用,只是在AES.new中多一个初始偏移向量。

*图4.14 AES加密设置*

*图4.15 解密 *** 作*

调用opencv中的函数,显示从摄像头读取的视频流、加密图像、噪声图像等;

*图4.16 显示 *** 作*

五、参考文献

[1] 薛沛林,张会汀,郑力明. 基于UDP/IP的多媒体数据传输[J].计算机工程与应用,2001,37(8):59-60,103. DOI:10.3321/j.issn:1002-8331.2001.08.021.

[2] 刘运强,王汇源. Socket和多线程在视频传输中的应用[J]. 山东大学学报(工学版),2004,34(2):46-50. DOI:10.3969/j.issn.1672-3961.2004.02.012.

[3] 高志国,李巧鸽,高新鹏. 视频监控数据远程传输的设计与实现[J]. 石油化工自动化,2010,46(5):51-53. DOI:10.3969/j.issn.1007-7324.2010.05.014.

[4] 曹秀霞. 基于TCP/IP协议的无线视频传输控制系统的设计与实现[D]. 陕西:西安电子科技大学,2013. DOI:10.7666/d.D363841.

[5] 董克基. 基于SOCKET的网络聊天系统分析设计[J]. 电子世界,2014(16):189-189. DOI:10.3969/j.issn.1003-0522.2014.16.185.

[6] 谭力菲,刘园珍,蔡友林. 基于Socket即时通讯软件设计[J]. 科技广场,2015(12):38-40. DOI:10.3969/j.issn.1671-4792.2015.12.008.

[7] 李新红. 音频功能网络聊天系统设计[J]. 信息通信,2013(8):62-63.

[8] 荣天琪,张宗杰,刘彤. 客户机/服务器模式的远程监控系统设计[J]. 应用科技,2013(2):1-4. DOI:10.3969/j.issn.1009-671X.201207014.

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/785780.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-04
下一篇 2022-05-04

发表评论

登录后才能评论

评论列表(0条)

保存