记一次renderdoc自动截帧

83 阅读4分钟

官方文档,官方文档写的真是一言难尽,看过的都懂

1、python 环境搭建:

github上下载renderdoc截帧工具,

然后使用Visual Studio打开源码根目录下的renderdoc.sln文件

打开后直接点击【生成解决方案】

image.png

编译好后会在源码根目录生成一个x64\Development目录, 目录结构如下图

image.png

pymodules就是关键目录了

ps: 如果想要使用其他版本的python:

到python所在目录,将lib目录整个压缩成pythonxx.zip, 以python37为例: 这里特别注意: 不是压缩lib, 而是压缩lib下的所有内容 image.png

然后右键点击qrenderdoc,按照下图的顺序进行设置

img_v3_02mv_bc3e1ff4-7169-43e1-9914-55ee8202eb8g.jpg

最后再生成解决方案即可

2、windows截帧

1)使用renderdoc打开被测试应用

此次的方案需要在已打开被测试应用的基础上进行

2)python中添加如下代码即可

import shutil
import sys
import os
import time

renderdoc = r'D:\pythonScripts\TestRenderDocTools\renderdoc'
os.environ["PATH"] += os.pathsep + os.path.abspath(renderdoc)
if sys.platform == 'win32' and sys.version_info[1] >= 8:
    os.add_dll_directory(renderdoc)

renderdoc_py = r"D:\pythonScripts\TestRenderDocTools\renderdoc\pymodules"
sys.path.append(renderdoc_py)
import renderdoc as rd


# 触发一次windows截帧并将截图保存至指定目录
def capture(savedPath):
    # 获取远程设备目标
    target_code = rd.EnumerateRemoteTargets("", 0)

    # # 创建目标控制连接
    targetControl = rd.CreateTargetControl(r"localhost", target_code, "capture_windows", True)
    if not targetControl:
        return False, '创建目标控制失败'
    # 进行一次截帧
    result = targetControl.TriggerCapture(1)

    # 等待截帧完成并将对应的数据放到指定目录
    startTime, isSuccess = time.time(), False
    while time.time()-startTime < 20:
        message = targetControl.ReceiveMessage(None)
        cap_path, cap_id, frame_num, api = message.newCapture.path, message.newCapture.captureId, message.newCapture.frameNumber, message.newCapture.api
        if cap_path:
            print(f'cap_path = {cap_path}, cap_id={cap_id}, frame_num={frame_num}, api={api}')
            # 将文件cppy到指定目录
            # 如果指定目录不存在则创建
            if not os.path.isdir(savedPath):
                os.makedirs(savedPath, exist_ok=True)

            # 将文件移动到指定目录
            shutil.move(cap_path, savedPath)

            isSuccess = True
            break

        time.sleep(1)

    if isSuccess:
        return True, '截帧成功'
    else:
        return False, '截帧超时失败'

capture(r'D:\RenderDoc\test')

3、android截帧

大体上android截帧跟windows截帧差别不是特别大:

1、都需要使用renderdoc打开被测试应用

2、都需要创建目标控制器,然后调用目标控制器中的截帧方法进行截帧 附上代码:

# 触发一次android截帧并将截图保存至指定目录
def capture_android(savedPath):
    # 初始化工具
    rd.InitialiseReplay(rd.GlobalEnvironment(), [])

    # 获取当前支持的设备协议
    protocols = rd.GetSupportedDeviceProtocols()
    print(f'protocols={protocols}')
    if len(protocols) == 0:
        return False, '没有支持的设备协议'

    # 获取设备协议控制器
    protocol = rd.GetDeviceProtocolController(protocols[0])
    print(f'protocol={protocol}')

    # 获取设备列表
    devices = protocol.GetDevices()
    print(f'device_list = {devices}')
    if len(devices) == 0:
        return False, '没有连接的设备'

    # 返回值类似这样: vivo V2217A
    device = protocol.GetFriendlyName(devices[0])
    print(f'device={device}')

    # 创建连接: 连接格式类似: "adb://10AC7X0HTA000UR", "adb://deviceId"
    URL = protocol.GetProtocolName() + "://" + devices[0]
    print(f'URL={URL}')

    print(f'IsSupported = {protocol.IsSupported(URL)}, SupportsMultiplePrograms={protocol.SupportsMultiplePrograms(URL)}, SupportsMultiplePrograms={protocol.SupportsMultiplePrograms(URL)}')

    ident = rd.EnumerateRemoteTargets(URL, 0)
    print(f'ident = {ident}')

    # 创建目标控制器
    targetControl = rd.CreateTargetControl(URL, ident, "capture_windows", True)

    # 进行一次截帧
    targetControl.TriggerCapture(1)

    # 等待截帧完成并将对应的数据放到指定目录
    startTime, isSuccess = time.time(), False
    while time.time() - startTime < 20:
        message = targetControl.ReceiveMessage(None)
        cap_path, cap_id, frame_num, api = message.newCapture.path, message.newCapture.captureId, message.newCapture.frameNumber, message.newCapture.api
        if cap_path:
            print(f'cap_path = {cap_path}, cap_id={cap_id}, frame_num={frame_num}, api={api}')
            # 将文件cppy到指定目录
            # 如果指定目录不存在则创建
            if not os.path.isdir(savedPath):
                os.makedirs(savedPath, exist_ok=True)

            # 将文件移动到指定目录
            newFileName = f'{datetime.now().strftime("%Y%m%d_%H%M%S")}.rdc'
            cmd = rf'{os.path.normpath(os.path.join(os.path.dirname(root_path), f"platform-tools/adb.exe"))} pull {cap_path} {os.path.normpath(os.path.join(savedPath, newFileName))}'
            os.system(cmd)
            isSuccess = True
            break

        time.sleep(1)

    if isSuccess:
        return True, '截帧成功'
    else:
        return False, '截帧超时失败'

4、pyinstaller打包

直接使用上述的脚本去进行截帧是没有问题的,但是,如果使用pyinstaller将脚本打包成exe,并将renderdoc打包进exe中,然后再执行exe,就会出现renderdoc加载不到的情况。非常诡异。

经过长时间调试,发现如果使用'--debug', 'all'打包选项进行打包,就可以正常运行。我也不知道是什么原理,先记录下来。后续有空了再深入研究

import subprocess

cmd = [
    r'C:\Python\python36\python.exe',
    '-m', 'PyInstaller',
    'main.py',  # 主脚本
    '--name', r'RenderDocTools',  # 工具名, 1.0.0: 大版本号: 用例迭代号: bug修复号
    '--debug', 'all',   # 是否打开更详细的日志
    '--onefile',  # 是否将包打成一个文件, 注释掉就是不打成一个文件
    # '--windowed',  # 是否开启调试窗口, 注释掉=开启
    '--add-binary', fr'D:\pythonScripts\TestRenderDocTools\renderdoc;renderdoc',   # 将renderdoc打包进exe中
]

subprocess.call(cmd)