|
本帖最后由 267646 于 2024-9-20 13:31 编辑
起因
Steam测试版开放了录制功能,可以在玩Steam游戏时自动录制,体验了几天,发现录像会有卡顿。例如我录了几小时真女神转生5复仇,游玩时非常流畅,但是录像几秒一卡。这点让我很不舒服,但是目前英伟达、OBS或其它录制软件并不支持自动录制,因此我萌生了用python写一个自动录制游戏程序的想法。
由于自己写一个录制软件是不现实的,因此该python程序的主要内容是:1. 自动监测需要录制的游戏;2. 当需要录制的游戏启动或停止时通知录像软件开始录制或停止录制(通过模拟快捷键实现)。
当然,录制软件需要开启,因为该Python程序并不负责录制的过程,只负责监测和通知录制软件。
英伟达和Windows自带的录制软件是默认开启的,OBS、bandicam等需要手动开启。
实现思路
1. 该python程序可以检测进程,当特定目录下(例如Steam游戏目录)的exe进程启动时,开始录制。当且仅当该进程结束时,停止录制。
2. 无关的进程名会被排除(加入黑名单),例如UnityCrashHandler32.exe或者一些不想录制的游戏(例如NBA 2K25)。
3. 除黑名单外,还需要有白名单,用于允许特定的进程触发录制。
4. 以上规则支持自行配置,配置内容放在一个txt文档中。
5. 开始录制和停止录制,利用python模拟按键实现。此时录制软件需要开启。
6. 该程序需要持续运行,每隔5秒就检测一次进程。
规则配置
基于以上思路,首先需要配置好规则,即什么游戏需要录制,什么游戏不需要录制。用什么快捷键去通知录制程序。
这些配置放在RecordingList.txt中,下面是一个示例的RecordingList.txt:
- [Hotkey]
- start, alt, f9
- stop, alt, f10
- [FilePath]
- D:\Steam\steamapps\common, 2
- D:\XboxGames, 2
- [WhiteList]
- D:\Steam\steamapps\common\Inari\UnityCrashHandler32.exe
- [BlackList]
- UnityCrashHandler32.exe
复制代码 [Hotkey]下面的内容是录制程序的开始录制和结束录制的快捷键。支持单个按键或者组合键。例如英伟达的录制程序,开始录制快捷键是alt+f9,那就填start, alt, f9
[FilePath]下面的内容用于匹配目录。
D:\Steam\steamapps\common, 2会匹配D:\Steam\steamapps\common的孙文件夹下的exe文件,例如D:\Steam\steamapps\common\SMT5V\SMT5V.exe。
这是Steam游戏目录的结构决定的,根据你自己的游戏目录灵活调整。同理D:\XboxGames, 2也会匹配D:\XboxGames的孙文件夹下的exe文件。
[WhiteList]下面的内容用于匹配白名单,[BlackList]下面的内容用于匹配黑名单。支持进程名和特定文件夹下的进程名。
GameRecording.py代码放在文章末尾,可以自行改动,如果不会也可以问GPT,我就是这么问来的。
实现步骤
下面是实现该功能的详细步骤:
1. 你需要安装python并将其加入系统环境变量中,从python官网下载后安装会自动帮你配置好,不用担心。
2. 该python程序用到了2个python库,psutil和ctypes,可以在控制台执行下面的命令来安装这两个库:
- pip install psutil
- pip install ctypes
复制代码 3. 选择一个文件夹,在该文件夹下新建2个文件:GameRecording.py和RecordingList.txt。GameRecording.py代码放在文章末尾。
4. 按照需求配置RecordingList.txt。如果改动了RecordingList.txt需要重新运行GameRecording.py。
5. 运行GameRecording.py。你可以在控制台中运行它,例如
- python D:\Code\Python\GameRecording\GameRecording.py
复制代码
详细代码及细节设置
1. 你可以将这个GameRecording.py加入开机自动启动列表,并前台运行,具体实现方式是在这个python程序下新建一个批处理文件,名字可以是start.bat,内容如下
- @echo off
- start "" "python.exe" "GameRecording.py"
复制代码 (如果要后台运行将上面代码中的python.exe改成pythonw.exe就可以了。)
然后按Windows+R,输入shell:startup
点击确定,在打开的文件夹中,右键新建快捷方式,点击浏览,选择刚才的新建的start.bat,然后一直下一步。
这样这个批处理就会开机自动启动运行GameRecording.py了。
2. 录制软件你可以使用任何录制软件,例如英伟达、Windows自带录制、bandicam等。
下面我以OBS为例,分享一下我的OBS设置。
使用OBS的原因是它免费,且支持NVENC HEVC录制,用到了N卡的硬件加速比较省资源,同时HEVC的编码体积较小,20Mbps的码率就很清晰了。如果是40系N卡可以尝试用AV1编码录制。
下面是我的OBS设置截图:
另外第一次用需要在OBS中设置采集为游戏采集,这样会只采集游戏内容,即便切出游戏也不会去采集桌面内容。
3. GameRecording.py代码
- import os
- import time
- import psutil
- import ctypes
- # Windows API 按键代码映射,包括 Windows 键
- key_map = {
- 'alt': 0x12,
- 'ctrl': 0x11,
- 'shift': 0x10,
- 'win': 0x5B, # 左侧 Windows 键
- 'f1': 0x70, 'f2': 0x71, 'f3': 0x72, 'f4': 0x73,
- 'f5': 0x74, 'f6': 0x75, 'f7': 0x76, 'f8': 0x77,
- 'f9': 0x78, 'f10': 0x79, 'f11': 0x7A, 'f12': 0x7B,
- 'a': 0x41, 'b': 0x42, 'c': 0x43, 'd': 0x44, 'e': 0x45,
- 'f': 0x46, 'g': 0x47, 'h': 0x48, 'i': 0x49, 'j': 0x4A,
- 'k': 0x4B, 'l': 0x4C, 'm': 0x4D, 'n': 0x4E, 'o': 0x4F,
- 'p': 0x50, 'q': 0x51, 'r': 0x52, 's': 0x53, 't': 0x54,
- 'u': 0x55, 'v': 0x56, 'w': 0x57, 'x': 0x58, 'y': 0x59,
- 'z': 0x5A, '0': 0x30, '1': 0x31, '2': 0x32, '3': 0x33,
- '4': 0x34, '5': 0x35, '6': 0x36, '7': 0x37, '8': 0x38,
- '9': 0x39, 'space': 0x20, 'enter': 0x0D, 'esc': 0x1B,
- 'tab': 0x09, 'backspace': 0x08, 'insert': 0x2D,
- 'delete': 0x2E, 'home': 0x24, 'end': 0x23,
- 'pageup': 0x21, 'pagedown': 0x22, 'left': 0x25,
- 'up': 0x26, 'right': 0x27, 'down': 0x28,
- }
- # 调用 Windows API 发送按键组合
- def press_key_combination(keys):
- for key in keys:
- ctypes.windll.user32.keybd_event(key, 0, 0, 0) # 按下按键
- time.sleep(0.05)
- for key in keys:
- ctypes.windll.user32.keybd_event(key, 0, 2, 0) # 释放按键
- # 检查进程是否在运行
- def is_process_running(exe_name):
- for proc in psutil.process_iter(['pid', 'name', 'exe']):
- try:
- if proc.info['name'] == exe_name or proc.info['exe'] == exe_name:
- return True
- except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
- pass
- return False
- # 检查是否被列入黑名单并不在白名单中
- def is_blacklisted(exe_path, whitelist, blacklist):
- exe_name = os.path.basename(exe_path)
- if exe_path in whitelist:
- return False # 白名单优先
- if exe_name in blacklist:
- return True
- return False
- # 获取文件夹及其子文件夹中的所有 .exe 文件
- def get_exe_files(folder_path, depth):
- exe_files = []
- for root, dirs, files in os.walk(folder_path):
- if root[len(folder_path):].count(os.sep) < depth:
- for file in files:
- if file.endswith(".exe"):
- exe_files.append(os.path.join(root, file))
- return exe_files
- # 动态获取脚本所在的目录
- script_dir = os.path.dirname(os.path.abspath(__file__))
- # 使用相对路径,基于脚本所在的目录查找 RecordingList.txt
- recording_list_path = os.path.join(script_dir, 'RecordingList.txt')
- # 解析 RecordingList.txt 文件,读取文件夹路径、白名单、黑名单和快捷键
- def load_recording_list():
- folder_paths = []
- whitelist = []
- blacklist = []
- hotkeys = {
- 'start': [],
- 'stop': []
- }
- # 打开基于相对路径的 RecordingList.txt 文件
- with open(recording_list_path, 'r') as file:
- lines = file.readlines()
- current_section = None
- for line in lines:
- line = line.strip()
- if not line or line.startswith('#') or line.startswith(';'): # 跳过注释
- continue
- if line == "[FilePath]":
- current_section = "FilePath"
- elif line == "[WhiteList]":
- current_section = "WhiteList"
- elif line == "[BlackList]":
- current_section = "BlackList"
- elif line == "[Hotkey]":
- current_section = "Hotkey"
- elif current_section == "FilePath" and line:
- parts = line.split(',')
- folder = parts[0].strip()
- depth = int(parts[1].strip())
- folder_paths.append((folder, depth))
- elif current_section == "WhiteList" and line:
- whitelist.append(line)
- elif current_section == "BlackList" and line:
- blacklist.append(line)
- elif current_section == "Hotkey" and line:
- parts = line.split(',')
- if parts[0].strip() == 'start':
- hotkeys['start'] = parse_hotkey(parts[1:])
- elif parts[0].strip() == 'stop':
- hotkeys['stop'] = parse_hotkey(parts[1:])
- return folder_paths, whitelist, blacklist, hotkeys
- # 解析快捷键
- def parse_hotkey(keys):
- parsed_keys = []
- for key in keys:
- key = key.strip().lower()
- if key in key_map:
- parsed_keys.append(key_map[key])
- return parsed_keys
- # 主函数
- def monitor_folders(folder_paths, whitelist, blacklist, hotkeys):
- running_status = {}
- active_process = None # 当前触发 F9 的进程
- # 获取所有文件夹下的可执行文件
- for folder_path, depth in folder_paths:
- exe_files = get_exe_files(folder_path, depth)
- for exe in exe_files:
- if not is_blacklisted(exe, whitelist, blacklist):
- running_status[exe] = False
- while True:
- if active_process is None: # 没有进程在活动状态
- for exe in running_status:
- process_running = is_process_running(exe)
- if process_running and not running_status[exe]:
- print(f"{exe} 已启动,按下快捷键组合...")
- press_key_combination(hotkeys['start']) # 按下开始的快捷键组合
- running_status[exe] = True
- active_process = exe # 设置当前活动进程
- break
- else: # 当前有一个进程在活动状态
- if not is_process_running(active_process):
- print(f"{active_process} 已停止,按下结束的快捷键组合...")
- press_key_combination(hotkeys['stop']) # 按下停止的快捷键组合
- running_status[active_process] = False
- active_process = None # 重置活动进程
- time.sleep(5) # 每5秒检测一次
- if __name__ == "__main__":
- # 读取 RecordingList.txt 获取文件夹路径、白名单、黑名单和快捷键
- folder_paths, whitelist, blacklist, hotkeys = load_recording_list()
- if folder_paths:
- monitor_folders(folder_paths, whitelist, blacklist, hotkeys)
- else:
- print("RecordingList.txt 中没有找到任何文件夹路径。")
复制代码 有任何问题欢迎问我或者问GPT
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
×
1、转载或引用本网站内容,必须注明本文网址:https://keylol.com/t968357-1-1。如发文者注明禁止转载,则请勿转载
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利
4、所有帖子仅代表作者本人意见,不代表本社区立场
|