def record_webcam(filename):
"""
cv2.VideoCapture(0, cv2.CAP_DSHOW)
参数1:打开前置摄像头参数是0,打开后置摄像头参数是1,如果多个摄像头,需要测试2,3其他参数,参数是视频文件路径则打开视频,如cap = cv2.VideoCapture(“../test.avi”)
参数2: ***设置cv2.CAP_DSHOW参数初始化摄像头,否则无法使用更高分辨率
***(win7需要使用cv2.CAP_DSHOW的方式初始化摄像头开始录屏,默认的方式(CAP_ANY),不能打开。win10和winserver可以使用默认的方式初始化摄像头)
"""
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
"""
***调用cv2.VideoWriter()方法保存视频之前需先设置摄像头,否则保存视频时设备的宽高不能生效
"""
cap.set(3, 640) # 视频流的帧的宽度
cap.set(4, 480) # 在视频流的帧的高度
print('开始录屏')
"""
***视频的帧率,即每秒传递的帧数。需要根据实现摄像头的帧率调整,达到最好的效果,否则,录制的视频可能偏快或者偏慢
"""
ftp = 22
"""
***使用设摄像头录制高清视频的时候一定要设置为MJPG,别的格式无法支持高清
"""
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))
aviFile = cv2.VideoWriter(filename,
cv2.VideoWriter_fourcc(*'MJPG'),
ftp, (640, 480), True)
print("初始化好摄像头之后开始录屏", str(datetime.now()))
while True:
ret, frame = cap.read()
if ret:
font = cv2.FONT_HERSHEY_SIMPLEX
datet = str(datetime.now())[:19].replace(":", "-")
frame = cv2.putText(frame, datet, (10, 30), font, 0.5,
(255, 255, 255), 1, cv2.LINE_AA) # 是视频里面显示时间或者文字
aviFile.write(frame)
cv2.imshow('frame', frame)
else:
break
print("结束录屏", str(datetime.now()))
aviFile.release()
cap.release()
注意 *** 标注的地方
"""
chunk_size: 每个缓冲区的帧数
channels: 单声道
rate: 采样频率
"""
CHUNK_SIZE = 1024
CHANNELS = 2
FORMAT = pyaudio.paInt16
RATE = 48000
allowRecording = True
def record_audio(filename):
p = pyaudio.PyAudio()
print('开始录音')
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK_SIZE
)
print("stream", str(datetime.now()))
wf = wave.open(filename, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
while allowRecording:
data = stream.read(CHUNK_SIZE)
wf.writeframes(data)
print("streame结束", str(datetime.now()))
wf.close()
stream.stop_stream()
stream.close()
p.terminate()
# # # 实现音频视频合成
print("video audio merge!!!!!")
audioclip = AudioFileClip(audio_filename)
videoclip = VideoFileClip(video_filename)
videoclip2 = videoclip.set_audio(audioclip)
video = CompositeVideoClip([videoclip2])
""" *** bitrate 设置比特率,比特率越高, 合并的视频越清晰,视频文件也越大,合并的速度会很慢"""
video.write_videofile(video_name, codec='mpeg4', bitrate='2000k')
依赖的版本
python==3.6.0
opencv-python==4.6.0.66 下载过程中会报错,但是可以使用
moviepy==1.0.3
PyAudio==0.2.11
完整的文件
# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : manage.py
# Time :2021/7/13 21:15
# Author : JuanZi
# version :python 3.6
# Description:
"""
import wave
import threading
from datetime import datetime, date, timedelta
import pyaudio
import cv2
from moviepy.editor import *
import time
import os
from ftplib import FTP
import socket # 主要用于获取当前主机IP地址
import requests
import json
from multiprocessing import Process, Queue
"""全局变量,主要控制录音和录屏的同步"""
allowRecording = False
Q = Queue()
def run_test(main_class, file_name):
marge = main_class()
marge.run(file_name)
class AudioThread(threading.Thread):
def __init__(self, event, filename):
threading.Thread.__init__(self)
self.p = pyaudio.PyAudio()
self.event = event
self.FORMAT = pyaudio.paInt16
self.stream = self.p.open(format= pyaudio.paInt16,
channels=2,
rate=48000,
input=True,
frames_per_buffer=1024
) # 打开数据流
self.wf = wave.open(filename, 'wb')
self.wf.setnchannels(2)
self.wf.setsampwidth(self.p.get_sample_size(self.FORMAT))
self.wf.setframerate(48000)
def run(self):
self.event.wait()
print('初始化完成,开始录音', str(datetime.now()))
while allowRecording:
data = self.stream.read(1024)
self.wf.writeframes(data)
self.wf.close()
self.stream.stop_stream() # 关闭流
self.stream.close()
self.p.terminate()
class VideoThread(threading.Thread):
"""
out 是VideoWriter的实列对象,就是写入视频的方式,第一个参数是存放写入视频的位置,
第二个是编码方式,20是帧率,最后是视频的高宽,如果录入视频为灰度,则还需加一个false
"""
def __init__(self, cap, event, filename):
threading.Thread.__init__(self)
self.event = event
self.cap = cap
self.cap.set(3, 640)
self.cap.set(4, 480)
fourcc = cv2.VideoWriter_fourcc(*'MJPG') # 设置视频编码方式,如果设置CAP_DSHOW的方式打开摄像头必须设置*'MJPG'的便码方式
fps = 15 + 0.000001 * 15
self.out = cv2.VideoWriter(filename, fourcc, fps, (640, 480))
def run(self):
"""
read()函数表示按帧读取视频,success,frame是read()的两个返回值,
ret是布尔值——如果读取帧是正确的则返回True,如果文件读取到结尾则返回False,Frame表示的是每一帧的图像,是一个三维矩阵
"""
time.sleep(0.5)
self.event.set()
print('初始化完成,开始录屏 %s',str(datetime.now()))
while allowRecording:
ret, frame = self.cap.read()
if ret:
font = cv2.FONT_HERSHEY_SIMPLEX
datet = str(datetime.now())[:19].replace(":", "-")
frame = cv2.putText(frame, datet, (10, 30), font, 0.5,
(255, 255, 255), 1, cv2.LINE_AA) # 是视频里面显示时间或者文字
cv2.imshow('frame', frame) # 显示视频
self.out.write(frame) # 写视频到视频文件
else:
break
self.out.release()
# 使用线程的方式合并音视频
class VideoMerge(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.cur_path = os.path.abspath(os.path.dirname(__file__))
self.path = self.cur_path + '\\static\\'
self.merge_path = self.path + 'merge\\'
self.Lock = threading.Lock()
self.need_video_merge = list()
self.init()
def init(self):
if not os.path.exists(self.path):
os.mkdir(self.path)
if not os.path.exists(self.merge_path):
os.mkdir(self.merge_path)
def run(self):
while True:
filename = None
with self.Lock:
if len(self.need_video_merge) > 0:
filename = self.need_video_merge[0]
if filename is not None:
try:
audio_filename = self.path + filename + '.mp3'
video_filename = self.path + filename + '.avi'
merge_filename = self.merge_path + filename + '.avi'
audioclip = AudioFileClip(audio_filename)
videoclip = VideoFileClip(video_filename)
videoclip2 = videoclip.set_audio(audioclip)
video = CompositeVideoClip([videoclip2])
video.write_videofile(merge_filename, codec='mpeg4', bitrate='2000k') # bitrate 设置比特率,比特率越高, 合并的视频越清晰,视频文件也越大
print("删除本地视频,音频文件……")
os.remove(video_filename)
os.remove(audio_filename)
self.need_video_merge.pop(0)
print("文件 %s 合并成功" % filename)
except Exception as e:
print("文件 %s 合并失败 %s" % (filename, e))
def push_list(self, filename):
with self.Lock:
self.need_video_merge.append(filename)
# 使用进程的方式合并音视频
# class VideoMerge():
# def __init__(self):
# self.cur_path = os.path.abspath(os.path.dirname(__file__))
# self.path = self.cur_path + '\\static\\'
# self.merge_path = self.path + 'merge\\'
# self.Lock = threading.Lock()
# self.need_video_merge = list()
# self.init()
#
# def init(self):
# if not os.path.exists(self.path):
# os.mkdir(self.path)
# if not os.path.exists(self.merge_path):
# os.mkdir(self.merge_path)
#
# def run(self, filename):
# if filename is not None:
# try:
# audio_filename = self.path + filename + '.mp3'
# video_filename = self.path + filename + '.avi'
# merge_filename = self.merge_path + filename + '.avi'
# audioclip = AudioFileClip(audio_filename)
# videoclip = VideoFileClip(video_filename)
# videoclip2 = videoclip.set_audio(audioclip)
# video = CompositeVideoClip([videoclip2])
# video.write_videofile(merge_filename, codec='mpeg4', bitrate='2000k') # bitrate 设置比特率,比特率越高, 合并的视频越清晰,视频文件也越大
# print("删除本地视频,音频文件……")
# os.remove(video_filename)
# os.remove(audio_filename)
# # self.need_video_merge.pop(0)
# print("文件 %s 合并成功" % filename)
# except Exception as e:
# print("文件 %s 合并失败 %s" % (filename, e))
class CameraRecord(object):
def __init__(self):
self.cap = None
self.p = None
self.video = None
self.audio = None
self.merge = None
self.event = threading.Event()
self.cur_time = ''
self.filename = ''
def init(self):
"""
参数1:打开前置摄像头参数是0,打开后置摄像头参数是1,如果多个摄像头,需要测试2,3其他参数,参数是视频文件路径则打开视频,如cap = cv2.VideoCapture(“../test.avi”)
参数2: 设置cv2.CAP_DSHOW参数初始化摄像头,否则无法使用更高分辨率
"""
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
print('打开系统摄像头')
# 使用线程的方式合并音视频
self.merge = VideoMerge()
self.merge.start()
def start_record(self):
if self.video is not None:
print('摄像功能正在使用中')
return False
global allowRecording
allowRecording = True
self.filename = str(datetime.now())[:19].replace(":", "-").replace(' ', "-").replace('-', "")
audio_filename = f'static\\{self.filename}.mp3'
video_filename = f'static\\{self.filename}.avi'
"""启用线程开始录音、录屏"""
self.video = VideoThread(self.cap, self.event, video_filename)
self.audio = AudioThread(self.event, audio_filename)
for t in (self.video, self.audio):
t.start()
def stop_record(self):
"""结束录屏"""
if self.video is None:
print('摄像功能没有在使用中')
return False
global allowRecording
allowRecording = False
self.video = None
self.audio = None
# 使用进程的方式去处理音视频的合并
self.merge.push_list(self.filename)
# 使用进程的方法处理音视频的合并,进度的启用开销大
# a = Process(target=run_test, args=(VideoMerge, self.filename))
# a.start()
# a.join()
print('此次录屏结束, 录屏开始时间:%s,' % self.filename)
if __name__ == '__main__':
camera = CameraRecord()
camera.init()
camera.start_record()
count = 30
while count:
count -= 1
print(count)
time.sleep(1)
camera.stop_record()
原创不易,有不对的地方望指正~