0.1
commit
d8e089f431
|
@ -0,0 +1,50 @@
|
|||
import re
|
||||
import RunCMD
|
||||
from RunCMD import run_cmd
|
||||
|
||||
class DevicesInfo():
|
||||
|
||||
def __init__(self):
|
||||
list_devices_cmd = 'ffmpeg -list_devices true -f dshow -i dummy'
|
||||
# status, output = subprocess.getstatusoutput(list_devices_cmd)
|
||||
output_err, output_str = run_cmd(list_devices_cmd)
|
||||
self.video_devices , self.voice_devices = self.extract_devices_info(''.join(output_err))
|
||||
|
||||
def get_device_info(self, text_list):
|
||||
device_list = []
|
||||
if text_list and len(text_list) % 2 == 0:
|
||||
i=0
|
||||
while i < len(text_list):
|
||||
step = 2
|
||||
device = []
|
||||
device_name = text_list[i].strip()
|
||||
device.append(device_name.replace('"',''))
|
||||
alternative_name_text = text_list[i+1]
|
||||
alter_re = re.search(r'"(.+)"',alternative_name_text)
|
||||
if alter_re:
|
||||
device_alternative_name = alter_re.group(1)
|
||||
device.append(device_alternative_name)
|
||||
device_list.append(device)
|
||||
i+=step
|
||||
return device_list
|
||||
|
||||
def extract_devices_info(self,devices_txt):
|
||||
device_line = []
|
||||
# print(dir(re))
|
||||
results = re.findall(r'\[[^\]]+\]([^\[]+)',devices_txt)
|
||||
# results.pop(0)
|
||||
video_devices_spos=-1
|
||||
voice_devices_spos=-1
|
||||
for i in range(len(results)):
|
||||
txt = results[i]
|
||||
# print(txt.strip())
|
||||
if txt.find('DirectShow video devices') >= 0:
|
||||
video_devices_spos = i
|
||||
if txt.find('DirectShow audio devices') >=0:
|
||||
voice_devices_spos = i
|
||||
|
||||
video_devices = self.get_device_info(results[video_devices_spos+1:voice_devices_spos])
|
||||
voice_devices = self.get_device_info(results[voice_devices_spos+1:])
|
||||
|
||||
return video_devices , voice_devices
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import os,configparser
|
||||
# import DevicesInfo
|
||||
# from DevicesInfo import *
|
||||
|
||||
class RecordConfig():
|
||||
def __init__(self, config_file_name = 'config.ini'):
|
||||
self.file_name = config_file_name
|
||||
self.encoding = 'gb2312'
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
|
||||
if os.path.exists(self.file_name):
|
||||
self.config=configparser.SafeConfigParser()
|
||||
self.config.read(self.file_name, encoding = self.encoding)
|
||||
else:
|
||||
self.write_default_config()
|
||||
self.load()
|
||||
|
||||
def write_default_config(self):
|
||||
print('初始化配置文件.')
|
||||
conf = configparser.SafeConfigParser()
|
||||
|
||||
# di = DevicesInfo()
|
||||
devices_section_name = 'devices'
|
||||
conf.add_section(devices_section_name)
|
||||
conf.set(devices_section_name,'camera_device_name','')
|
||||
conf.set(devices_section_name,'voice_device_name','')
|
||||
conf.set(devices_section_name,'screen_device_name','')
|
||||
conf.set(devices_section_name,'system_voice_device_name','')
|
||||
|
||||
shortcut_section_name = 'shortcut'
|
||||
conf.add_section(shortcut_section_name)
|
||||
conf.set(shortcut_section_name,'camera','160,162,164,65')
|
||||
conf.set(shortcut_section_name,'screen','160,162,164,66')
|
||||
conf.set(shortcut_section_name,'stop','160,162,164,67')
|
||||
|
||||
record_section_name = 'record'
|
||||
conf.add_section(record_section_name)
|
||||
conf.set(record_section_name,'resolution','1920x1080')
|
||||
conf.set(record_section_name,'vcodec','libx264')
|
||||
conf.set(record_section_name,'frame_rate','7.0')
|
||||
conf.set(record_section_name,'file_dir','.')
|
||||
|
||||
self.config = conf
|
||||
self.write()
|
||||
|
||||
def write(self):
|
||||
with open(self.file_name, 'wt', encoding = self.encoding) as configfp:
|
||||
self.config.write(configfp)
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import sys,os
|
||||
from PyQt5 import QtWidgets,QtGui
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
import RecordType
|
||||
from RecordType import *
|
||||
|
||||
class RecordTrayIcon(QSystemTrayIcon):
|
||||
def __init__(self, parent=None):
|
||||
super(RecordTrayIcon, self).__init__(parent)
|
||||
# print((p_menu.actions()))
|
||||
# self.showAction1 = QAction("显示消息1", self, triggered=self.showM)
|
||||
# print(type(self.parent))
|
||||
# p_menu.insertAction(p_menu.actions()[len(p_menu.actions())-1], self.showAction1)
|
||||
|
||||
# self.showMenu()
|
||||
self.createContextMenu(parent)
|
||||
self.interactive()
|
||||
# self.update_state(False,None)
|
||||
|
||||
|
||||
def createContextMenu(self, parent):
|
||||
p_menu = parent.contextMenu
|
||||
self.setContextMenu(p_menu)
|
||||
|
||||
def interactive(self):
|
||||
self.activated.connect(self.iconClicked)
|
||||
self.toolTip()
|
||||
|
||||
def showMessage():
|
||||
pass
|
||||
|
||||
def get_icon(self, file_name):
|
||||
|
||||
data_dir=''
|
||||
|
||||
if getattr(sys, 'frozen', False):
|
||||
# The application is frozen
|
||||
data_dir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
# The application is not frozen
|
||||
# Change this bit to match where you store your data files:
|
||||
data_dir = os.path.dirname(__file__)
|
||||
|
||||
resource_dir = 'resource'
|
||||
data_dir = os.path.join(os.path.abspath(data_dir), resource_dir)
|
||||
print('resource dir: %s' % data_dir)
|
||||
|
||||
icon_file_path = os.path.join(data_dir, file_name)
|
||||
if os.path.isfile(icon_file_path):
|
||||
return QIcon(icon_file_path)
|
||||
return None
|
||||
|
||||
def update_state(self, recording, record_type):
|
||||
|
||||
if recording:
|
||||
if record_type == RecordType.Camera:
|
||||
self.setIcon(self.get_icon('camera_recording_colorful.png'))
|
||||
self.setToolTip('正在录制摄像头...')
|
||||
|
||||
elif record_type == RecordType.Screen:
|
||||
self.setIcon(self.get_icon('screen_recording.png'))
|
||||
self.setToolTip('正在录制屏幕...')
|
||||
else:
|
||||
self.setIcon(self.get_icon('stop.png'))
|
||||
self.setToolTip('软件缩小在这里.')
|
||||
else:
|
||||
self.setIcon(self.get_icon('start.png'))
|
||||
self.setToolTip('软件缩小在这里.')
|
||||
|
||||
|
||||
def iconClicked(self, reason):
|
||||
#"鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击"
|
||||
if reason == 2 or reason == 3:
|
||||
pw = self.parent()
|
||||
if pw.isVisible() and pw.isActiveWindow():
|
||||
pw.hide()
|
||||
else:
|
||||
pw.show()
|
||||
# pw.raise_()
|
||||
pw.activateWindow()
|
||||
# print('parent is active window? %s' % pw.isActiveWindow())
|
||||
# print(reason)
|
|
@ -0,0 +1,7 @@
|
|||
from enum import Enum
|
||||
|
||||
class RecordType(Enum):
|
||||
#摄像头
|
||||
Camera = 0
|
||||
#屏幕
|
||||
Screen = 1
|
|
@ -0,0 +1,250 @@
|
|||
import datetime,time,sys,os,signal,re
|
||||
from datetime import datetime
|
||||
import subprocess,threading
|
||||
# from multiprocessing import Process
|
||||
from threading import Thread
|
||||
import ctypes,inspect
|
||||
import RecordType
|
||||
from RecordType import *
|
||||
import RecordConfig
|
||||
from RecordConfig import *
|
||||
import logging
|
||||
import RunCMD
|
||||
from RunCMD import run_cmd
|
||||
|
||||
class RecordVideo():
|
||||
|
||||
|
||||
'''
|
||||
ffmpeg -f dshow -i video="@device_pnp_\\\\?\\usb#vid_04f2&pid_b354&mi_00#7&30d7ad30&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global":audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{571529B3-7DB3-42A3-ADEF-BBD82925C15D}" -acodec libmp3lame -vcodec libx265 -preset:v ultrafast -tune:v zerolatency -s 1920x1080 -r 7 -y record_camera_20180408_182541.mkv
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, record_video=True, record_voice=True):
|
||||
# print('视频录制初始化中...')
|
||||
# self.record_video=record_video
|
||||
# self.record_voice=record_voice
|
||||
#录制状态
|
||||
self.recording=False
|
||||
self.record_type=RecordType.Camera
|
||||
#文件名称
|
||||
self.file_name='record'
|
||||
#文件后缀
|
||||
self.file_suffix='.mkv'
|
||||
self.process = None
|
||||
self.record_thread_name='record'
|
||||
self.record_thread=None
|
||||
|
||||
self.file_dir = ''
|
||||
self.load_config()
|
||||
|
||||
|
||||
def load_config(self):
|
||||
|
||||
#日志
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.logger.setLevel(level = logging.INFO)
|
||||
handler = logging.FileHandler('log.txt')
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
self.logger.addHandler(handler)
|
||||
|
||||
rc = RecordConfig()
|
||||
self.config = rc.config
|
||||
|
||||
#摄像头名称
|
||||
self.camera_name=rc.config.get('devices','camera_device_name')
|
||||
#麦克风名称
|
||||
self.voice_device_name=rc.config.get('devices','voice_device_name')
|
||||
#录制屏幕名称
|
||||
self.screen_name=rc.config.get('devices','screen_device_name')
|
||||
#系统声音设备名称
|
||||
self.system_voice_device_name=rc.config.get('devices','system_voice_device_name')
|
||||
#视频编码
|
||||
self.video_codec=rc.config.get('record','vcodec')
|
||||
#分辨率
|
||||
self.resolution=rc.config.get('record','resolution')
|
||||
#帧率
|
||||
self.brate=rc.config.getfloat('record','frame_rate')
|
||||
#文件目录
|
||||
self.file_dir= os.path.abspath(rc.config.get('record','file_dir'))
|
||||
|
||||
self.logger.info('camera device name: %s' % self.camera_name)
|
||||
self.logger.info('voice device name: %s' % self.voice_device_name)
|
||||
self.logger.info('screen device name: %s' % self.screen_name)
|
||||
self.logger.info('system voice device name: %s' % self.system_voice_device_name)
|
||||
self.logger.info('vcodec: %s' % self.video_codec)
|
||||
self.logger.info('resolution: %s' % self.resolution)
|
||||
self.logger.info('frame rate: %s' % self.brate)
|
||||
self.logger.info('save dir: %s' % self.file_dir)
|
||||
|
||||
def start_ffmpeg(self,cmd, shell = True):
|
||||
print('录制中...')
|
||||
self.logger.info('录制中...')
|
||||
# print('cmd:\n%s' % cmd)
|
||||
start_time = datetime.now()
|
||||
self.process=subprocess.Popen(cmd, shell=shell, universal_newlines = True, stdin = subprocess.PIPE, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
|
||||
# print(self.process.stdin)
|
||||
line = ''
|
||||
while self.recording:
|
||||
|
||||
line += self.process.stdout.readline()
|
||||
now = datetime.now()
|
||||
if (now - start_time).total_seconds() >2:
|
||||
self.logger.info(line)
|
||||
line = ''
|
||||
start_time = now
|
||||
|
||||
print(line)
|
||||
|
||||
if not self.recording:
|
||||
self.process.stdin.write('q')
|
||||
print(self.process.communicate())
|
||||
break
|
||||
|
||||
# self.logger.info(self.process.communicate())
|
||||
# print('done.')
|
||||
|
||||
def record(self,cmd='ffmpeg -h', target = None):
|
||||
|
||||
if target:
|
||||
print('cmd: \n%s' % cmd)
|
||||
self.logger.info('record cmd:\n %s' % cmd)
|
||||
th=Thread(name=self.record_thread_name, target= target, args = (cmd,), daemon=True)
|
||||
th.start()
|
||||
self.record_thread=th
|
||||
print('record thread,ident:%d' % self.record_thread.ident)
|
||||
self.recording=True
|
||||
|
||||
def stop_record(self):
|
||||
|
||||
# print('threading active thread count:%d' % threading.active_count())
|
||||
try:
|
||||
|
||||
self.recording = False
|
||||
self.logger.info('ffmpeg pid: %d' % self.process.pid)
|
||||
self.logger.info('录制将停止...')
|
||||
self.logger.info('ffmpeg进程状态: %s' % (self.process.poll() is not None))
|
||||
self.recording=False
|
||||
if self.record_thread.is_alive():
|
||||
self.record_thread.join(1)
|
||||
print('record thread status: %s' % self.record_thread.is_alive())
|
||||
except (Exception,KeyboardInterrupt) as e:
|
||||
print('kill exception:\n %s' % e)
|
||||
self.logger.warning('kill exception:\n %s' % e)
|
||||
|
||||
def record_camera(self):
|
||||
|
||||
if self.camera_name and self.voice_device_name:
|
||||
|
||||
self.record_type=RecordType.Camera
|
||||
record_cmd='ffmpeg -f dshow -i video=\"%s\":audio=\"%s\" -acodec libmp3lame -vcodec %s -preset:v ultrafast -tune:v zerolatency -s %s -r %d -y %s' %(
|
||||
self.deal_with_device_name(self.camera_name),
|
||||
self.deal_with_device_name(self.voice_device_name),
|
||||
self.video_codec,
|
||||
self.resolution,
|
||||
self.brate,
|
||||
self.get_file_name()
|
||||
)
|
||||
# print(record_cmd)
|
||||
self.record(record_cmd, self.start_ffmpeg)
|
||||
|
||||
def record_screen(self):
|
||||
if self.screen_name and self.system_voice_device_name:
|
||||
self.record_type=RecordType.Screen
|
||||
record_cmd='ffmpeg -f dshow -i video="{}":audio="{}" -acodec libmp3lame -vcodec {} -preset:v ultrafast -tune:v zerolatency -s {} -r {} -y {}'.format(
|
||||
self.deal_with_device_name(self.screen_name),
|
||||
self.deal_with_device_name(self.system_voice_device_name),
|
||||
self.video_codec,
|
||||
self.resolution,
|
||||
self.brate,
|
||||
self.get_file_name()
|
||||
)
|
||||
self.record(record_cmd, self.start_ffmpeg)
|
||||
|
||||
|
||||
def debug_camera(self):
|
||||
try:
|
||||
play_cmd = ['ffplay','-f','dshow','-i','video={}'.format(self.camera_name),'-window_title','按q退出','-noborder']
|
||||
self.record(play_cmd, self.play)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def play(self, cmd):
|
||||
try:
|
||||
t_process=subprocess.Popen(cmd, shell= False, universal_newlines = True, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
|
||||
while True:
|
||||
line = t_process.stdout.readline()
|
||||
print(line)
|
||||
if line == '':
|
||||
if t_process.poll() is not None:
|
||||
break
|
||||
t_process.communicate()
|
||||
except (Exception, KeyboardInterrupt) as e:
|
||||
print(e)
|
||||
|
||||
def deal_with_device_name(self,device_name):
|
||||
# print(device_name)
|
||||
# new_name=device_name.replace('\\','\\\\')
|
||||
# print(new_name)
|
||||
# return new_name
|
||||
return device_name
|
||||
|
||||
def get_file_name(self):
|
||||
time_str=datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
video_type = ''
|
||||
if self.record_type == RecordType.Camera:
|
||||
video_type = '摄像头'
|
||||
if self.record_type == RecordType.Screen:
|
||||
video_type = '屏幕'
|
||||
|
||||
file_name = os.path.join(self.file_dir, '{}_{}{}'.format(video_type, time_str, self.file_suffix))
|
||||
print('recording file name: %s' % file_name)
|
||||
return file_name
|
||||
|
||||
def _async_raise(self, tid, exctype):
|
||||
"""raises the exception, performs cleanup if needed"""
|
||||
tid = ctypes.c_long(tid)
|
||||
if not inspect.isclass(exctype):
|
||||
exctype = type(exctype)
|
||||
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
|
||||
print('async_raise res value:%d' % res)
|
||||
if res == 0:
|
||||
raise ValueError("invalid thread id")
|
||||
elif res != 1:
|
||||
# """if it returns a number greater than one, you're in trouble,
|
||||
# and you should call it again with exc=NULL to revert the effect"""
|
||||
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
|
||||
raise SystemError("PyThreadState_SetAsyncExc failed")
|
||||
|
||||
def kill_process(self, process_name='ffmpeg'):
|
||||
cmd='tasklist | findstr {}'.format(process_name)
|
||||
output_strs, output_errs=self.run_cmd(cmd)
|
||||
pid=[]
|
||||
if output_strs:
|
||||
print('find "%s" result: \n%s' % (process_name, ''.join(output_strs)))
|
||||
for output_str in output_strs:
|
||||
find_re=re.search(r'({}.+?)\s*([0-9]+)'.format(process_name),output_str)
|
||||
if find_re:
|
||||
full_process_name=find_re.group(1).strip()
|
||||
pid=find_re.group(2).strip()
|
||||
print('计划结束任务:{}@pid: {}'.format( full_process_name, pid ))
|
||||
task_kill_cmd = 'taskkill /T /F /pid {}'.format(pid)
|
||||
# status, output = subprocess.getstatusoutput(task_kill_cmd)
|
||||
|
||||
# if status == 1:
|
||||
# print('任务成功被结束:')
|
||||
# else:
|
||||
# print('任务结束失败:')
|
||||
# print(output)
|
||||
|
||||
else:
|
||||
print('not found task about "%s" in tasklist' % process_name )
|
||||
|
||||
|
||||
# def stop_thread(self,thread):
|
||||
# self._async_raise(thread.ident, SystemExit)
|
||||
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
import sys, datetime
|
||||
import PyQt5
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt, QCoreApplication
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
import RecordVideo,RecordType
|
||||
from RecordVideo import *
|
||||
from RecordType import *
|
||||
import SettingWindow
|
||||
from SettingWindow import *
|
||||
import Shortcut
|
||||
from Shortcut import *
|
||||
import RecordTrayIcon
|
||||
from RecordTrayIcon import *
|
||||
import RecordConfig
|
||||
from RecordConfig import *
|
||||
|
||||
class RecordWindow(QtWidgets.QWidget):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super(RecordWindow,self).__init__(parent)
|
||||
self.setupUi()
|
||||
self.load_modules()
|
||||
#更新设置
|
||||
self.need_update_config = False
|
||||
#初始化状态
|
||||
print('初始化状态...')
|
||||
self.update_state()
|
||||
|
||||
def load_modules(self):
|
||||
#录制
|
||||
self.rv=RecordVideo()
|
||||
#鼠标拖动
|
||||
self.m_drag = False
|
||||
#托盘图标
|
||||
self.rti = RecordTrayIcon(self)
|
||||
self.rti.update_state(self.recording, self.record_type)
|
||||
|
||||
self.rc = RecordConfig()
|
||||
|
||||
self.file_dir = self.rc.config.get('record','file_dir')
|
||||
self.debugCameraAction.triggered.connect(self.rv.debug_camera)
|
||||
|
||||
def closeEvent(self, event):
|
||||
# print('close window.')
|
||||
# self.close_signal.emit()
|
||||
# self.close()
|
||||
# if self.recording:
|
||||
|
||||
# question = QMessageBox(self)
|
||||
# question.setText('系统正在录制中,确定要退出吗?')
|
||||
# question.setWindowTitle('提示')
|
||||
# question.setIcon(QMessageBox.Question)
|
||||
# question.addButton(QMessageBox.Yes)
|
||||
# question.addButton(QMessageBox.No)
|
||||
# question.setDefaultButton(QMessageBox.No)
|
||||
# ret = question.exec()
|
||||
# if ret == QMessageBox.Yes:
|
||||
# self.stop_record()
|
||||
# QCoreApplication.instance().quit()
|
||||
|
||||
# else:
|
||||
|
||||
# question = QMessageBox()
|
||||
# question.setText('确定要退出吗?')
|
||||
# question.setWindowTitle('提示')
|
||||
# question.setIcon(QMessageBox.Question)
|
||||
# question.addButton(QMessageBox.Yes)
|
||||
# question.addButton(QMessageBox.No)
|
||||
# question.setDefaultButton(QMessageBox.No)
|
||||
# ret = question.exec()
|
||||
# if ret == QMessageBox.Yes:
|
||||
# print('软件将退出.')
|
||||
QCoreApplication.instance().quit()
|
||||
|
||||
# event.ignore()
|
||||
|
||||
|
||||
|
||||
def setupUi(self):
|
||||
self.setObjectName("RecordWindow")
|
||||
self.resize(94, 81)
|
||||
self.move(1100,600)
|
||||
self.pushButton = QtWidgets.QPushButton(self)
|
||||
self.pushButton.setGeometry(QtCore.QRect(0, 30, 91, 51))
|
||||
self.pushButton.setObjectName("pushButton")
|
||||
# self.pushButton.mousePressEvent.connect(self.mousePressEvent)
|
||||
# print(dir(self.pushButton))
|
||||
|
||||
#添加右键菜单
|
||||
self.createContextMenu()
|
||||
|
||||
#添加计时器
|
||||
self.lcd = QLCDNumber(self)
|
||||
self.lcd.setDigitCount(10)
|
||||
self.lcd.setMode(QLCDNumber.Dec)
|
||||
self.lcd.setGeometry(QtCore.QRect(0, 0, 91, 31))
|
||||
self.lcd.setSegmentStyle(QLCDNumber.Flat)
|
||||
self.init_lcd()
|
||||
|
||||
#新建一个QTimer对象
|
||||
self.timer = QTimer()
|
||||
self.timer.setInterval(1000)
|
||||
self.timer.timeout.connect(self.onTimerOut)
|
||||
|
||||
self.retranslateUi()
|
||||
|
||||
#调整窗体属性
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool)
|
||||
# self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.installEventFilter(self)
|
||||
|
||||
|
||||
def retranslateUi(self):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
self.setWindowTitle(_translate("RecordWindow", "RecordWindow"))
|
||||
self.pushButton.setText(_translate("RecordWindow", "开始"))
|
||||
|
||||
|
||||
def init_lcd(self):
|
||||
self.lcd.display('0:00:00')
|
||||
|
||||
def start_timer(self):
|
||||
self.start_time = datetime.now()
|
||||
self.init_lcd()
|
||||
self.timer.start()
|
||||
|
||||
def stop_timer(self):
|
||||
self.timer.stop()
|
||||
self.init_lcd()
|
||||
|
||||
# 刷新录制时间
|
||||
def onTimerOut(self):
|
||||
self.lcd.display(self.get_display_time(self.start_time))
|
||||
|
||||
def get_display_time(self,old_time):
|
||||
delta_time = datetime.now() - old_time
|
||||
delta_time_str = str(delta_time)
|
||||
pos = delta_time_str.find('.')
|
||||
time_text = delta_time_str[0:pos]
|
||||
return time_text
|
||||
|
||||
#打开文件目录
|
||||
def open_file_dir(self):
|
||||
dirpath = self.file_dir
|
||||
if os.path.isdir(dirpath):
|
||||
os.startfile(dirpath)
|
||||
else:
|
||||
print('错误的文件目录:%s' % dirpath)
|
||||
|
||||
#显示菜单
|
||||
def showContextMenu(self):
|
||||
self.contextMenu.exec_(QtGui.QCursor.pos())
|
||||
|
||||
#添加右键菜单
|
||||
def createContextMenu(self):
|
||||
#更改右键菜单为自定义
|
||||
print('初始化右键菜单...')
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.showContextMenu)
|
||||
|
||||
self.contextMenu = QtWidgets.QMenu(self)
|
||||
#停止/开始录制
|
||||
self.recordSwitchAction = self.contextMenu.addAction('开始/停止录制')
|
||||
#开始录制摄像头
|
||||
self.recordCameraAction = self.contextMenu.addAction('开始录制摄像头')
|
||||
#录制屏幕
|
||||
self.recordScreenAction = self.contextMenu.addAction('开始录制屏幕')
|
||||
#分隔栏
|
||||
self.separatorAction = self.contextMenu.addAction('分隔栏')
|
||||
self.separatorAction.setSeparator(True)
|
||||
self.openFileDirAction = self.contextMenu.addAction('打开文件目录')
|
||||
self.openFileDirAction.triggered.connect(self.open_file_dir)
|
||||
#调试摄像头
|
||||
self.debugCameraAction = self.contextMenu.addAction('调试摄像头')
|
||||
self.debugCameraAction.setVisible(False)
|
||||
#设置
|
||||
self.settingAction=self.contextMenu.addAction('设置')
|
||||
self.sw = SettingWindow()
|
||||
self.settingAction.triggered.connect(self.sw.showSettingWindow)
|
||||
#帮助
|
||||
self.aboutAction=self.contextMenu.addAction('帮助')
|
||||
#退出
|
||||
self.exitAction = self.contextMenu.addAction('退出')
|
||||
self.exitAction.triggered.connect(self.close)
|
||||
|
||||
|
||||
'''
|
||||
功能事件
|
||||
|
||||
|
||||
'''
|
||||
|
||||
@property
|
||||
def recording(self):
|
||||
return self.rv.recording
|
||||
|
||||
@property
|
||||
def record_type(self):
|
||||
return self.rv.record_type
|
||||
|
||||
def register_slot(self, event_obj, new_action, disconnect = True):
|
||||
if disconnect:
|
||||
try:
|
||||
event_obj.disconnect()
|
||||
except Exception as e:
|
||||
pass
|
||||
event_obj.connect(new_action)
|
||||
|
||||
def update_state(self):
|
||||
|
||||
if self.recording:
|
||||
print('录制状态:录制中.')
|
||||
|
||||
if self.record_type == RecordType.Camera:
|
||||
print('正在录制摄像头.')
|
||||
else:
|
||||
print('正在录制屏幕.')
|
||||
print('recording:%s' % self.recording)
|
||||
print('record_type:%s' % self.record_type)
|
||||
|
||||
if self.recording:
|
||||
self.recordSwitchAction.setText('停止录制')
|
||||
self.register_slot(self.pushButton.clicked, self.stop_record)
|
||||
self.register_slot(self.recordSwitchAction.triggered, self.stop_record)
|
||||
|
||||
#正在录制摄像头
|
||||
if self.record_type == RecordType.Camera:
|
||||
self.pushButton.setText('正在录制摄像头\n点击停止')
|
||||
self.recordCameraAction.setText('停止录制摄像头')
|
||||
self.register_slot(self.recordCameraAction.triggered, self.stop_record)
|
||||
|
||||
self.recordScreenAction.setText('开始录制屏幕')
|
||||
self.register_slot(self.recordScreenAction.triggered, lambda: self.record(RecordType.Screen))
|
||||
#正在录制屏幕
|
||||
if self.record_type == RecordType.Screen:
|
||||
|
||||
self.pushButton.setText('正在录制屏幕\n点击停止')
|
||||
self.recordScreenAction.setText('停止录制屏幕')
|
||||
self.register_slot(self.recordScreenAction.triggered, self.stop_record)
|
||||
|
||||
self.recordCameraAction.setText('开始录制摄像头')
|
||||
self.register_slot(self.recordCameraAction.triggered, lambda: self.record(RecordType.Camera))
|
||||
|
||||
else:
|
||||
self.pushButton.setText('开始')
|
||||
self.recordSwitchAction.setText('开始录制')
|
||||
self.register_slot(self.pushButton.clicked, lambda: self.record(self.record_type))
|
||||
self.register_slot(self.recordSwitchAction.triggered, lambda: self.record(self.record_type))
|
||||
|
||||
self.recordScreenAction.setText('开始录制屏幕')
|
||||
self.register_slot(self.recordScreenAction.triggered, lambda: self.record(RecordType.Screen))
|
||||
|
||||
self.recordCameraAction.setText('开始录制摄像头')
|
||||
self.register_slot(self.recordCameraAction.triggered, lambda: self.record(RecordType.Camera))
|
||||
|
||||
self.rti.update_state(self.recording, self.record_type)
|
||||
|
||||
def stop_record(self):
|
||||
|
||||
if self.recording:
|
||||
self.stop_timer()
|
||||
|
||||
if self.record_type == RecordType.Camera:
|
||||
print('停止录制摄像头.')
|
||||
|
||||
if self.record_type == RecordType.Screen:
|
||||
print('停止录制屏幕.')
|
||||
|
||||
try:
|
||||
self.rv.stop_record()
|
||||
except KeyboardInterrupt as e:
|
||||
print(e)
|
||||
finally:
|
||||
self.update_state()
|
||||
else:
|
||||
#退出系统
|
||||
self.close()
|
||||
|
||||
def record(self, rtype):
|
||||
|
||||
if self.recording:
|
||||
if rtype == self.record_type:
|
||||
return True
|
||||
|
||||
print('检测到正在录制,录制类型将切换...')
|
||||
self.stop_record()
|
||||
|
||||
#开始录制
|
||||
if rtype == RecordType.Camera:
|
||||
print('开始录制摄像头...')
|
||||
self.rv.record_camera()
|
||||
elif rtype == RecordType.Screen:
|
||||
print('开始录制屏幕...')
|
||||
self.rv.record_screen()
|
||||
|
||||
self.start_timer()
|
||||
self.update_state()
|
||||
|
||||
''''
|
||||
鼠标拖动窗体
|
||||
|
||||
'''
|
||||
|
||||
def mousePressEvent(self, e):
|
||||
if not isinstance(self,RecordWindow):
|
||||
e.ignore()
|
||||
else:
|
||||
if e.button() == Qt.LeftButton:
|
||||
self.m_drag = True
|
||||
self.m_DragPosition = e.globalPos() - self.pos()
|
||||
e.accept()
|
||||
self.setCursor(QtGui.QCursor(Qt.OpenHandCursor))
|
||||
|
||||
def mouseReleaseEvent(self, e):
|
||||
if not isinstance(self,RecordWindow):
|
||||
e.ignore()
|
||||
else:
|
||||
if e.button() == Qt.LeftButton:
|
||||
self.m_drag = False
|
||||
self.setCursor(QtGui.QCursor(Qt.ArrowCursor))
|
||||
|
||||
def mouseMoveEvent(self, e):
|
||||
if not isinstance(self,RecordWindow):
|
||||
e.ignore()
|
||||
else:
|
||||
if Qt.LeftButton and self.m_drag:
|
||||
self.move(e.globalPos() - self.m_DragPosition)
|
||||
e.accept()
|
||||
|
||||
# print('(x:%d/y:%d)' % (self.x(),self.y()))
|
||||
|
||||
'''
|
||||
快捷键监听
|
||||
|
||||
'''
|
||||
|
||||
def monitor_shortcut(self):
|
||||
|
||||
sc = Shortcut()
|
||||
|
||||
camera_key_group = self.rc.config.get('shortcut','camera')
|
||||
screen_key_group = self.rc.config.get('shortcut','screen')
|
||||
stop_record_key_group = self.rc.config.get('shortcut','stop')
|
||||
|
||||
camera_shortcut = [int(key) for key in camera_key_group.split(',')]
|
||||
screen_shortcut = [int(key) for key in screen_key_group.split(',')]
|
||||
stop_shortcut = [int(key) for key in stop_record_key_group.split(',')]
|
||||
|
||||
print('camera shortcut: %s' % camera_shortcut)
|
||||
print('screen shortcut: %s' % screen_shortcut)
|
||||
print('stop shortcut: %s' % stop_shortcut)
|
||||
|
||||
if camera_key_group:
|
||||
sc.add(1, camera_shortcut, lambda: self.record(RecordType.Camera))
|
||||
if screen_key_group:
|
||||
sc.add(2, screen_shortcut, lambda: self.record(RecordType.Screen))
|
||||
if stop_record_key_group:
|
||||
sc.add(3, stop_shortcut, self.stop_record)
|
||||
sc.monitor()
|
||||
|
||||
'''
|
||||
窗体事件
|
||||
'''
|
||||
def eventFilter(self, obj, event):
|
||||
# print('e type: %s' % event.type())
|
||||
# print('deactivate type id :%d' % QEvent.WindowDeactivate)
|
||||
if event.type() == QEvent.WindowDeactivate:
|
||||
# print('丢失焦点')
|
||||
self.setVisible(False)
|
||||
|
||||
return False
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
rw = RecordWindow()
|
||||
rw.monitor_shortcut()
|
||||
rw.rti.show()
|
||||
rw.show()
|
||||
sys.exit(app.exec_())
|
|
@ -0,0 +1,28 @@
|
|||
import subprocess
|
||||
|
||||
def run_cmd(cmd, shell = True, universal_newlines = False):
|
||||
output_info=[]
|
||||
output_err=[]
|
||||
with subprocess.Popen(cmd,
|
||||
shell = shell,
|
||||
universal_newlines = universal_newlines,
|
||||
stdout = subprocess.PIPE,
|
||||
stdin = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE
|
||||
) as p:
|
||||
while True:
|
||||
info=str(p.stdout.read(), encoding ='utf-8')
|
||||
# print(dir(p.stderr))
|
||||
# print(info)
|
||||
err=str(p.stderr.read(), encoding = 'utf-8')
|
||||
# print(err)
|
||||
if not info and not err:
|
||||
if p.poll() is not None:
|
||||
break
|
||||
else:
|
||||
output_info.append(info)
|
||||
output_err.append(err)
|
||||
|
||||
return output_err, output_info
|
||||
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
from PyQt5 import QtWidgets,QtCore
|
||||
from PyQt5.QtWidgets import QFileDialog
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.QtCore import *
|
||||
import DevicesInfo
|
||||
from DevicesInfo import *
|
||||
import RecordConfig
|
||||
from RecordConfig import *
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
class SettingWindow(QDialog):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super(SettingWindow,self).__init__(parent)
|
||||
self.setupUi()
|
||||
self.load()
|
||||
|
||||
def setupUi(self):
|
||||
self.setObjectName("SettingWindow")
|
||||
self.resize(386, 238)
|
||||
self.tabWidget = QtWidgets.QTabWidget(self)
|
||||
self.tabWidget.setGeometry(QtCore.QRect(10, 10, 371, 221))
|
||||
self.tabWidget.setObjectName("tabWidget")
|
||||
self.tab_device = QtWidgets.QWidget()
|
||||
self.tab_device.setObjectName("tab_device")
|
||||
self.gridLayoutWidget_3 = QtWidgets.QWidget(self.tab_device)
|
||||
self.gridLayoutWidget_3.setGeometry(QtCore.QRect(10, 10, 321, 171))
|
||||
self.gridLayoutWidget_3.setObjectName("gridLayoutWidget_3")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.gridLayoutWidget_3)
|
||||
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.label_3 = QtWidgets.QLabel(self.gridLayoutWidget_3)
|
||||
self.label_3.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_3.setWordWrap(False)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout_3.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
self.cb_camera_devices = QtWidgets.QComboBox(self.gridLayoutWidget_3)
|
||||
self.cb_camera_devices.setObjectName("devices.camera_device_name")
|
||||
self.gridLayout_3.addWidget(self.cb_camera_devices, 0, 1, 1, 1)
|
||||
self.cb_voice_devices = QtWidgets.QComboBox(self.gridLayoutWidget_3)
|
||||
self.cb_voice_devices.setObjectName("devices.voice_device_name")
|
||||
self.gridLayout_3.addWidget(self.cb_voice_devices, 1, 1, 1, 1)
|
||||
self.cb_screen_devices = QtWidgets.QComboBox(self.gridLayoutWidget_3)
|
||||
self.cb_screen_devices.setObjectName("devices.screen_device_name")
|
||||
self.gridLayout_3.addWidget(self.cb_screen_devices, 2, 1, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(self.gridLayoutWidget_3)
|
||||
self.label_2.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_2.setWordWrap(False)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout_3.addWidget(self.label_2, 1, 0, 1, 1)
|
||||
self.label = QtWidgets.QLabel(self.gridLayoutWidget_3)
|
||||
self.label.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label.setWordWrap(False)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(self.gridLayoutWidget_3)
|
||||
self.label_4.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.label_4.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_4.setWordWrap(False)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout_3.addWidget(self.label_4, 3, 0, 1, 1)
|
||||
self.cb_system_voice_devices = QtWidgets.QComboBox(self.gridLayoutWidget_3)
|
||||
self.cb_system_voice_devices.setObjectName("devices.system_voice_device_name")
|
||||
self.gridLayout_3.addWidget(self.cb_system_voice_devices, 3, 1, 1, 1)
|
||||
self.tabWidget.addTab(self.tab_device, "")
|
||||
self.tab_key = QtWidgets.QWidget()
|
||||
self.tab_key.setObjectName("tab_key")
|
||||
self.gridLayoutWidget_2 = QtWidgets.QWidget(self.tab_key)
|
||||
self.gridLayoutWidget_2.setGeometry(QtCore.QRect(10, 10, 321, 121))
|
||||
self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2")
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
|
||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.le_start_record_screen_shortcut = QtWidgets.QLineEdit(self.gridLayoutWidget_2)
|
||||
self.le_start_record_screen_shortcut.setObjectName("shortcut.screen")
|
||||
self.gridLayout_2.addWidget(self.le_start_record_screen_shortcut, 1, 1, 1, 1)
|
||||
self.label_10 = QtWidgets.QLabel(self.gridLayoutWidget_2)
|
||||
self.label_10.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label_10.setTextFormat(QtCore.Qt.AutoText)
|
||||
self.label_10.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_10.setObjectName("label_10")
|
||||
self.gridLayout_2.addWidget(self.label_10, 1, 0, 1, 1)
|
||||
self.le_start_record_camera_shortcut = QtWidgets.QLineEdit(self.gridLayoutWidget_2)
|
||||
self.le_start_record_camera_shortcut.setObjectName("shortcut.camera")
|
||||
self.gridLayout_2.addWidget(self.le_start_record_camera_shortcut, 0, 1, 1, 1)
|
||||
self.label_9 = QtWidgets.QLabel(self.gridLayoutWidget_2)
|
||||
self.label_9.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label_9.setTextFormat(QtCore.Qt.AutoText)
|
||||
self.label_9.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.gridLayout_2.addWidget(self.label_9, 0, 0, 1, 1)
|
||||
self.label_11 = QtWidgets.QLabel(self.gridLayoutWidget_2)
|
||||
self.label_11.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label_11.setTextFormat(QtCore.Qt.AutoText)
|
||||
self.label_11.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_11.setObjectName("label_11")
|
||||
self.gridLayout_2.addWidget(self.label_11, 2, 0, 1, 1)
|
||||
self.le_start_stop_exit_shortcut = QtWidgets.QLineEdit(self.gridLayoutWidget_2)
|
||||
self.le_start_stop_exit_shortcut.setObjectName("shortcut.stop")
|
||||
self.gridLayout_2.addWidget(self.le_start_stop_exit_shortcut, 2, 1, 1, 1)
|
||||
self.tabWidget.addTab(self.tab_key, "")
|
||||
self.tab_record = QtWidgets.QWidget()
|
||||
self.tab_record.setObjectName("tab_record")
|
||||
self.gridLayoutWidget = QtWidgets.QWidget(self.tab_record)
|
||||
self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 321, 161))
|
||||
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
|
||||
self.gridLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout.setHorizontalSpacing(0)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_14 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
self.label_14.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_14.setObjectName("label_14")
|
||||
self.gridLayout.addWidget(self.label_14, 1, 0, 1, 1)
|
||||
self.cb_resolution = QtWidgets.QComboBox(self.gridLayoutWidget)
|
||||
self.cb_resolution.setObjectName("record.resolution")
|
||||
self.gridLayout.addWidget(self.cb_resolution, 0, 1, 1, 1)
|
||||
self.cb_vcodec = QtWidgets.QComboBox(self.gridLayoutWidget)
|
||||
self.cb_vcodec.setObjectName("record.vcodec")
|
||||
self.gridLayout.addWidget(self.cb_vcodec, 1, 1, 1, 1)
|
||||
self.dsb_frame_rate = QtWidgets.QDoubleSpinBox(self.gridLayoutWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.dsb_frame_rate.sizePolicy().hasHeightForWidth())
|
||||
self.dsb_frame_rate.setSizePolicy(sizePolicy)
|
||||
self.dsb_frame_rate.setObjectName("record.frame_rate")
|
||||
self.gridLayout.addWidget(self.dsb_frame_rate, 2, 1, 1, 1)
|
||||
self.label_15 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
self.label_15.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_15.setObjectName("label_15")
|
||||
self.gridLayout.addWidget(self.label_15, 2, 0, 1, 1)
|
||||
self.le_file_path = QtWidgets.QLineEdit(self.gridLayoutWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.le_file_path.sizePolicy().hasHeightForWidth())
|
||||
self.le_file_path.setSizePolicy(sizePolicy)
|
||||
self.le_file_path.setObjectName("record.file_dir")
|
||||
self.gridLayout.addWidget(self.le_file_path, 4, 1, 1, 1)
|
||||
self.label_13 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
self.label_13.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_13.setObjectName("label_13")
|
||||
self.gridLayout.addWidget(self.label_13, 4, 0, 1, 1)
|
||||
self.label_12 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
self.label_12.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_12.setObjectName("label_12")
|
||||
self.gridLayout.addWidget(self.label_12, 0, 0, 1, 1)
|
||||
self.btn_file_dir = QtWidgets.QToolButton(self.gridLayoutWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_file_dir.sizePolicy().hasHeightForWidth())
|
||||
self.btn_file_dir.setSizePolicy(sizePolicy)
|
||||
self.btn_file_dir.setObjectName("btn_file_dir")
|
||||
self.gridLayout.addWidget(self.btn_file_dir, 4, 2, 1, 1)
|
||||
self.tabWidget.addTab(self.tab_record, "")
|
||||
self.frame = QtWidgets.QFrame(self)
|
||||
self.frame.setGeometry(QtCore.QRect(60, 330, 229, 10))
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
|
||||
self.retranslateUi()
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
def retranslateUi(self):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
self.setWindowTitle(_translate("Form", "设置-Development By Linxiao"))
|
||||
self.label_3.setText(_translate("Form", "屏幕录制设备:"))
|
||||
self.label_2.setText(_translate("Form", "声音输入设备:"))
|
||||
self.label.setText(_translate("Form", "摄像头名称:"))
|
||||
self.label_4.setText(_translate("Form", "系统声音设备:"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_device), _translate("Form", "设备参数配置"))
|
||||
self.label_10.setText(_translate("Form", "录制屏幕:"))
|
||||
self.label_9.setText(_translate("Form", "录制摄像头:"))
|
||||
self.label_11.setText(_translate("Form", "启动/退出:"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_key), _translate("Form", "快捷键设置"))
|
||||
self.label_14.setText(_translate("Form", "编码格式:"))
|
||||
self.label_15.setText(_translate("Form", "帧率:"))
|
||||
self.label_13.setText(_translate("Form", "文件保存目录:"))
|
||||
self.label_12.setText(_translate("Form", "分辨率:"))
|
||||
self.btn_file_dir.setText(_translate("Form", "选择文件目录"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_record), _translate("Form", "录制参数"))
|
||||
|
||||
|
||||
|
||||
# def set_combobox_select_index_by_name_or_data(self, combobox, name_or_data):
|
||||
# for i in range(len()
|
||||
def load_combobox_data(self, combox, data):
|
||||
for obj in data:
|
||||
name = obj[0]
|
||||
value = name
|
||||
if len(obj) > 1:
|
||||
value = obj[1]
|
||||
combox.addItem(name, value)
|
||||
|
||||
def get_key_group_name(self, key_tuple):
|
||||
return key_tuple.replace(r'(','').replace(r')','')
|
||||
|
||||
|
||||
def load(self):
|
||||
|
||||
|
||||
rc = RecordConfig()
|
||||
self.rc = rc
|
||||
self.changed = False
|
||||
'''
|
||||
数据初始化
|
||||
'''
|
||||
#设备
|
||||
di = DevicesInfo()
|
||||
self.load_combobox_data(self.cb_camera_devices, di.video_devices)
|
||||
self.load_combobox_data(self.cb_screen_devices, di.video_devices)
|
||||
self.load_combobox_data(self.cb_voice_devices, di.voice_devices)
|
||||
self.load_combobox_data(self.cb_system_voice_devices, di.voice_devices)
|
||||
|
||||
#录制
|
||||
resolutions = [
|
||||
['1920x1080'],
|
||||
['1280x1024'],
|
||||
['1024x768'],
|
||||
['640x480']
|
||||
]
|
||||
|
||||
vcodec = [
|
||||
['H.264','libx264'],
|
||||
['H.265','libx265'],
|
||||
]
|
||||
self.load_combobox_data(self.cb_resolution, resolutions)
|
||||
self.load_combobox_data(self.cb_vcodec, vcodec)
|
||||
|
||||
# print(self.cb_camera_devices.currentData())
|
||||
# print('视频设备列表:')
|
||||
# print(di.video_devices)
|
||||
# print('音频设备列表:')
|
||||
# print(di.voice_devices)
|
||||
|
||||
'''
|
||||
加载设置
|
||||
'''
|
||||
#设备
|
||||
video_device_name = rc.config.get('devices','camera_device_name')
|
||||
voice_device_name = rc.config.get('devices','voice_device_name')
|
||||
screen_device_name = rc.config.get('devices','screen_device_name')
|
||||
system_voice_device_name = rc.config.get('devices','system_voice_device_name')
|
||||
|
||||
# self.cb_camera_devices.setCurrentIndex(1)
|
||||
video_cur_index = self.cb_camera_devices.findData(video_device_name)
|
||||
# print('video name:\n%s\ndevice index:%d' % (video_device_name, video_cur_index))
|
||||
self.cb_camera_devices.setCurrentIndex(video_cur_index)
|
||||
|
||||
self.cb_voice_devices.setCurrentIndex(self.cb_voice_devices.findData(voice_device_name))
|
||||
self.cb_screen_devices.setCurrentIndex(self.cb_screen_devices.findData(screen_device_name))
|
||||
self.cb_system_voice_devices.setCurrentIndex(self.cb_system_voice_devices.findData(system_voice_device_name))
|
||||
|
||||
#快捷键
|
||||
record_camera_key_group = rc.config.get('shortcut','camera')
|
||||
record_screen_key_group = rc.config.get('shortcut','screen')
|
||||
record_stop_key_group = rc.config.get('shortcut','stop')
|
||||
|
||||
record_camera_key_group_name = self.get_key_group_name(record_camera_key_group)
|
||||
record_screen_key_group_name = self.get_key_group_name(record_screen_key_group)
|
||||
record_stop_key_group_name = self.get_key_group_name(record_stop_key_group)
|
||||
|
||||
self.le_start_record_camera_shortcut.setText(record_camera_key_group_name)
|
||||
self.le_start_record_screen_shortcut.setText(record_screen_key_group_name)
|
||||
self.le_start_stop_exit_shortcut.setText(record_stop_key_group_name)
|
||||
|
||||
#录制参数
|
||||
record_resolution = self.rc.config.get('record','resolution')
|
||||
record_vcodec = self.rc.config.get('record','vcodec')
|
||||
record_frame_rate = self.rc.config.getfloat('record','frame_rate')
|
||||
record_file_dir = self.rc.config.get('record','file_dir')
|
||||
record_file_dir = os.path.abspath(record_file_dir)
|
||||
|
||||
self.cb_resolution.setCurrentIndex(self.cb_resolution.findData(record_resolution))
|
||||
self.cb_vcodec.setCurrentIndex(self.cb_vcodec.findData(record_vcodec))
|
||||
self.dsb_frame_rate.setDecimals(1)
|
||||
self.dsb_frame_rate.setValue(record_frame_rate)
|
||||
self.le_file_path.setText(record_file_dir)
|
||||
|
||||
'''
|
||||
关联事件
|
||||
'''
|
||||
#设备
|
||||
self.cb_camera_devices.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_camera_devices))
|
||||
self.cb_voice_devices.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_voice_devices))
|
||||
self.cb_screen_devices.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_screen_devices))
|
||||
self.cb_system_voice_devices.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_system_voice_devices))
|
||||
|
||||
#快捷键
|
||||
self.le_start_record_camera_shortcut.textChanged.connect(lambda: self.textChangedEvent(self.le_start_record_camera_shortcut))
|
||||
self.le_start_record_screen_shortcut.textChanged.connect(lambda: self.textChangedEvent(self.le_start_record_screen_shortcut))
|
||||
self.le_start_stop_exit_shortcut.textChanged.connect(lambda: self.textChangedEvent(self.le_start_stop_exit_shortcut))
|
||||
|
||||
#录制参数
|
||||
self.cb_resolution.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_resolution))
|
||||
self.cb_vcodec.currentIndexChanged.connect(lambda: self.indexChangedEvent(self, self.cb_vcodec))
|
||||
self.dsb_frame_rate.valueChanged.connect(self.valueChangedEvent)
|
||||
self.le_file_path.textChanged.connect(lambda: self.textChangedEvent(self.le_file_path))
|
||||
|
||||
# self.le_start_record_camera_shortcut.keyPressEvent = self.record_keypress
|
||||
# print(dir(self.le_start_record_camera_shortcut.keyPressEvent))
|
||||
|
||||
|
||||
# self.le_file_path.setText()
|
||||
self.btn_file_dir.clicked.connect(self.file_dir_select)
|
||||
|
||||
|
||||
def record_keypress(self, event):
|
||||
print('text:%s' %event.text())
|
||||
print('key:%d' % event.key())
|
||||
print('modifiers: %s' % event.modifiers())
|
||||
print('nativeVirtualKey:%s' % event.nativeVirtualKey())
|
||||
|
||||
def file_dir_select(self, event):
|
||||
current_dir = self.le_file_path.text()
|
||||
if os.path.exists(current_dir):
|
||||
selected_dir = QFileDialog.getExistingDirectory(self, '选择录像保存目录', current_dir, QFileDialog.ShowDirsOnly)
|
||||
self.le_file_path.setText(selected_dir)
|
||||
|
||||
def showSettingWindow(self):
|
||||
if not self.isVisible():
|
||||
self.exec_()
|
||||
|
||||
def closeEvent(self, event):
|
||||
print('changed?%s' % self.changed)
|
||||
if self.changed:
|
||||
|
||||
self.save_setting()
|
||||
|
||||
question = QMessageBox(self)
|
||||
question.setText('设置已保存,重新启动软件生效。')
|
||||
question.setWindowTitle('提示')
|
||||
question.setIcon(QMessageBox.Question)
|
||||
question.addButton(QMessageBox.Yes)
|
||||
question.exec()
|
||||
print('parent is None?%s' % (self.parent is None))
|
||||
self.changed = False
|
||||
|
||||
self.setVisible(False)
|
||||
event.ignore()
|
||||
|
||||
def save_setting(self):
|
||||
self.rc.write()
|
||||
|
||||
def setting(self, obj_name, value):
|
||||
|
||||
section = ''
|
||||
name = ''
|
||||
if obj_name.find('.') >= 0:
|
||||
section = obj_name.split('.')[0]
|
||||
name = obj_name.split('.')[1]
|
||||
if type(value) == type(''):
|
||||
value = value.strip()
|
||||
print('check param in index changed:')
|
||||
print('section:%s' % section)
|
||||
print('name:%s' % name )
|
||||
print('value:%s' % value)
|
||||
|
||||
if self.rc.config.has_option(section, name):
|
||||
|
||||
self.changed = True
|
||||
self.rc.config.set(section, name, value)
|
||||
else:
|
||||
pass
|
||||
print('not found this section or name.')
|
||||
|
||||
def indexChangedEvent(self, index, obj):
|
||||
|
||||
# print('in data changed event.')
|
||||
print(index)
|
||||
print('event obj:%s' % type(obj))
|
||||
print('obj name:%s' % obj.objectName())
|
||||
|
||||
value = obj.currentData()
|
||||
obj_name = obj.objectName()
|
||||
self.setting(obj_name, value)
|
||||
|
||||
def textChangedEvent(self, obj):
|
||||
|
||||
# print('type of self:%s' % type(self))
|
||||
# print('type of text:%s' % type(text))
|
||||
# print('type of obj:%s' % type(obj))
|
||||
value = obj.text()
|
||||
obj_name = obj.objectName()
|
||||
self.setting(obj_name, value)
|
||||
|
||||
def valueChangedEvent(self):
|
||||
print('in value changed event.')
|
||||
obj = self.dsb_frame_rate
|
||||
value = obj.value()
|
||||
print('value:%1.f' % value)
|
||||
obj_name = obj.objectName()
|
||||
self.setting(obj_name, str(value))
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
import PyHook3
|
||||
import pythoncom
|
||||
|
||||
class Shortcut():
|
||||
|
||||
global HOTKEYS
|
||||
global ACTIONS
|
||||
global KEY_STATUS
|
||||
global PRESSED_COUNT
|
||||
|
||||
HOTKEYS = {}
|
||||
ACTIONS = {}
|
||||
KEY_STATUS = {}
|
||||
PRESSED_COUNT = {}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def add(self, key_group_id , key_group, action):
|
||||
global HOTKEYS
|
||||
global ACTIONS
|
||||
|
||||
HOTKEYS[key_group_id] = key_group
|
||||
ACTIONS[key_group_id] = action
|
||||
|
||||
def KeyDownEvent(self, event):
|
||||
global KEY_STATUS
|
||||
global HOTKEYS
|
||||
global PRESSED_COUNT
|
||||
global ACTIONS
|
||||
|
||||
#标记状态
|
||||
KEY_STATUS[event.KeyID] = True
|
||||
# print('HOTKEYS: \n%s' % HOTKEYS)
|
||||
# print('KEY DOWN/press key status: \n %s' % KEY_STATUS)
|
||||
|
||||
for action_id, key_group in HOTKEYS.items():
|
||||
#检查每个按键状态
|
||||
pressed = True
|
||||
for i in range(len(key_group)):
|
||||
key = key_group[i]
|
||||
if key not in KEY_STATUS:
|
||||
pressed = False
|
||||
break
|
||||
|
||||
if pressed:
|
||||
# if action_id not in PRESSED_COUNT.keys():
|
||||
# PRESSED_COUNT[action_id] =1
|
||||
# else:
|
||||
# PRESSED_COUNT[action_id] +=1
|
||||
print('match.')
|
||||
#限制一直按下快捷键 动作执行的次数
|
||||
if action_id not in PRESSED_COUNT.keys():
|
||||
action=ACTIONS[action_id]
|
||||
if action:
|
||||
action()
|
||||
PRESSED_COUNT[action_id] =1
|
||||
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def KeyUpEvent(self, event):
|
||||
global KEY_STATUS
|
||||
global HOTKEYS
|
||||
global PRESSED_COUNT
|
||||
global ACTIONS
|
||||
|
||||
if event.KeyID in KEY_STATUS.keys():
|
||||
KEY_STATUS.pop(event.KeyID)
|
||||
# print('KEY UP/press key status: \n %s' % KEY_STATUS)
|
||||
|
||||
#清空组合按键记录
|
||||
for action_id, key_group in HOTKEYS.items():
|
||||
if event.KeyID in key_group:
|
||||
if action_id in PRESSED_COUNT.keys():
|
||||
PRESSED_COUNT.pop(action_id)
|
||||
|
||||
return True
|
||||
|
||||
def monitor(self):
|
||||
|
||||
# create the hook mananger
|
||||
hm = PyHook3.HookManager()
|
||||
# hm.MouseAllButtonsDown = OnMouseEvent
|
||||
hm.KeyDown = self.KeyDownEvent
|
||||
hm.KeyUp = self.KeyUpEvent
|
||||
|
||||
hm.HookKeyboard()
|
||||
# pythoncom.PumpMessages()
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue