VS中对.fx文件进行Custom Build的设置

本文介绍了如何在Visual Studio(VS)中为Direct3D的.fx文件设置自定义构建步骤,以直接调用fxc.exe编译器进行编译。通过在项目的属性设置中选择Custom Build Tool,并在Command Line中输入编译命令,可以实现编译和错误定位。这种方法提高了编译效率,允许在Output窗口中双击错误行直接定位问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      对于D3D中.fx文件进行编译可以直接使用D3D Tools中的fxc.exe,或是在程序运行后加载.fx文件的时间调用fx编译器进行编译,但这样种种不便。受CUDA文件编译设置的启发,同样可以对.fx进行custom build设置,进而直接调用fxc.exe进行编译。

      首先,对于.fx文件,右键->Properties,进行属性设置;Tool选为:Custom Build Tool



然后Custom Build Step -> General -> Command Line, 输入下述语句(直接复制即可):

"$(DXSDK_DIR)Utilities\bin\x86\fxc.exe" /Gec /T fx_2_0 /Fc$(InputDir)\$(InputName).txt /Fo$(InputDir)\$(InputName).fxo %(Filename).fx $(Input

import sys import os import tkinter as tk from tkinter import ttk, filedialog, messagebox import cv2 import numpy as np import random from datetime import datetime, timedelta import threading import subprocess import shutil # 设置DPI感知,确保在高分辨率屏幕上显示正常 try: from ctypes import windll windll.shcore.SetProcessDpiAwareness(1) except: pass # 尝试导入可选依赖 MOVIEPY_AVAILABLE = False PSUTIL_AVAILABLE = False # 处理打包后的导入问题 if getattr(sys, 'frozen', False): # 运行在打包环境中 base_path = sys._MEIPASS # 添加可能的包路径 for package in ['moviepy', 'imageio', 'imageio_ffmpeg', 'psutil']: package_path = os.path.join(base_path, package) if os.path.exists(package_path): sys.path.insert(0, package_path) else: # 正常运行时 base_path = os.path.dirname(__file__) try: from moviepy.editor import VideoFileClip, AudioFileClip MOVIEPY_AVAILABLE = True except ImportError as e: print(f"MoviePy import error: {e}") try: import psutil PSUTIL_AVAILABLE = True except ImportError: pass # 全局变量 stop_processing = False # 定义核心处理函数 def add_invisible_overlay(frame, strength): """核心功能:添加全透明扰动层(对抗哈希检测)""" # 将强度从0-100映射到更合理的扰动范围 (1-5) overlay_strength = strength / 100.0 * 4 + 1 # 1 to 5 # 1. 创建一个和帧大小一样的随机噪声图像 noise = np.random.randn(*frame.shape).astype(np.float32) * overlay_strength # 2. 将噪声加到原帧上 new_frame = frame.astype(np.float32) + noise # 3. 确保像素值在0-255之间 new_frame = np.clip(new_frame, 0, 255).astype(np.uint8) return new_frame def resize_with_padding(frame, target_width=720, target_height=1560): """将帧调整为目标分辨率,保持宽高比,不足部分用黑色填充""" # 获取原始尺寸 h, w = frame.shape[:2] # 计算缩放比例 scale = target_width / w new_h = int(h * scale) # 如果缩放后的高度超过目标高度,则按高度缩放 if new_h > target_height: scale = target_height / h new_w = int(w * scale) resized = cv2.resize(frame, (new_w, target_height)) else: resized = cv2.resize(frame, (target_width, new_h)) # 创建目标画布(黑色) canvas = np.zeros((target_height, target_width, 3), dtype=np.uint8) # 计算放置位置(居中) y_offset = (target_height - resized.shape[0]) // 2 x_offset = (target_width - resized.shape[1]) // 2 # 将缩放后的图像放到画布上 canvas[y_offset:y_offset+resized.shape[0], x_offset:x_offset+resized.shape[1]] = resized # 在黑色区域添加不可见的随机噪声(亮度值0-5) black_areas = np.where(canvas == 0) if len(black_areas[0]) > 0: # 只对黑色区域添加噪声 noise = np.random.randint(0, 6, size=black_areas[0].shape, dtype=np.uint8) for i in range(3): # 对RGB三个通道 canvas[black_areas[0], black_areas[1], i] = noise return canvas def generate_random_metadata(): """生成随机的元数据""" # 随机设备型号列表 devices = [ "iPhone15,3", "iPhone15,2", "iPhone14,2", "iPhone14,1", "SM-G998B", "SM-G996B", "SM-G781B", "Mi 11 Ultra", "Mi 10", "Redmi Note 10 Pro" ] # 随机应用程序列表 apps = [ "Wxmm_9020230808", "Wxmm_9020230701", "Wxmm_9020230605", "LemonCamera_5.2.1", "CapCut_9.5.0", "VivaVideo_9.15.5" ] # 随机生成创建时间(最近30天内) now = datetime.now() random_days = random.randint(0, 30) random_hours = random.randint(0, 23) random_minutes = random.randint(0, 59) random_seconds = random.randint(0, 59) creation_time = now - timedelta(days=random_days, hours=random_hours, minutes=random_minutes, seconds=random_seconds) return { "device_model": random.choice(devices), "writing_application": random.choice(apps), "creation_time": creation_time.strftime("%Y-%m-%dT%H:%M:%S"), "title": f"Video_{random.randint(10000, 99999)}", "artist": "Mobile User", "compatible_brands": "isom,iso2,avc1,mp41", "major_brand": "isom" } def corrupt_metadata(input_path, output_path, custom_metadata=None, gpu_type="cpu"): """使用FFmpeg深度修改元数据""" if custom_metadata is None: custom_metadata = generate_random_metadata() # 根据GPU类型设置编码器 if gpu_type == "nvidia": video_encoder = "h264_nvenc" elif gpu_type == "amd": video_encoder = "h264_amf" elif gpu_type == "intel": video_encoder = "h264_qsv" else: video_encoder = "libx264" # 构造FFmpeg命令 command = [ 'ffmpeg', '-i', input_path, '-map_metadata', '-1', # 丢弃所有元数据 '-metadata', f'title={custom_metadata["title"]}', '-metadata', f'artist={custom_metadata["artist"]}', '-metadata', f'creation_time={custom_metadata["creation_time"]}', '-metadata', f'compatible_brands={custom_metadata["compatible_brands"]}', '-metadata', f'major_brand={custom_metadata["major_brand"]}', '-metadata', f'handler_name={custom_metadata["writing_application"]}', '-movflags', 'use_metadata_tags', '-c:v', video_encoder, '-preset', 'medium', '-crf', str(random.randint(18, 23)), # 随机CRF值 '-profile:v', 'high', '-level', '4.0', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-b:a', '96k', '-ar', '44100', '-y', output_path ] # 添加设备特定元数据 if 'iPhone' in custom_metadata["device_model"]: command.extend([ '-metadata', f'com.apple.quicktime.model={custom_metadata["device_model"]}', '-metadata', f'com.apple.quicktime.software=16.0' ]) try: subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True except subprocess.CalledProcessError as e: print(f"FFmpeg error: {e}") return False except FileNotFoundError: messagebox.showerror('致命错误', '错误:未找到FFmpeg!\n请确保ffmpeg.exe在程序同一目录下。') return False def create_background_video(output_path, duration, width=720, height=1560, fps=30): """创建带有扰动的黑色背景视频""" # 使用FFmpeg创建带有随机噪声的黑色背景视频 cmd = [ 'ffmpeg', '-f', 'lavfi', '-i', f'nullsrc=s={width}x{height}:d={duration}:r={fps}', '-vf', 'noise=alls=20:allf=t', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-y', output_path ] try: subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True except subprocess.CalledProcessError as e: print(f"创建背景视频失败: {e}") return False def detect_gpu(): """检测可用的GPU类型""" try: # 尝试使用nvidia-smi检测NVIDIA GPU try: result = subprocess.run(['nvidia-smi'], capture_output=True, text=True, check=True) if result.returncode == 0: return "nvidia" except (subprocess.CalledProcessError, FileNotFoundError): pass # 尝试使用Windows Management Instrumentation检测AMD和Intel GPU try: import wmi w = wmi.WMI() for gpu in w.Win32_VideoController(): name = gpu.Name.lower() if "amd" in name or "radeon" in name: return "amd" elif "intel" in name: return "intel" except ImportError: pass # 尝试使用dxdiag检测GPU try: result = subprocess.run(['dxdiag', '/t', 'dxdiag.txt'], capture_output=True, text=True, check=True) if result.returncode == 0: with open('dxdiag.txt', 'r', encoding='utf-16') as f: content = f.read().lower() if "nvidia" in content: return "nvidia" elif "amd" in content or "radeon" in content: return "amd" elif "intel" in content: return "intel" except (subprocess.CalledProcessError, FileNotFoundError): pass except Exception as e: print(f"GPU检测失败: {e}") return "cpu" def add_audio_watermark(audio_clip, strength): """给音频添加水印(简化版本)""" # 在实际应用中,这里应该实现音频扰动算法 # 这里只是一个示例,返回原始音频 return audio_clip def process_video(): """主处理流程控制器""" global stop_processing if not MOVIEPY_AVAILABLE: messagebox.showerror("错误", "MoviePy库未安装!请运行: pip install moviepy") return False input_path = input_entry.get() output_path = output_entry.get() if not input_path or not output_path: messagebox.showerror('错误', '请先选择输入和输出文件!') return False # 解析用户选择的强度和功能 strength = strength_scale.get() use_video_perturb = video_var.get() use_audio_perturb = audio_var.get() use_metadata_corrupt = metadata_var.get() use_gan = gan_var.get() use_resize = resize_var.get() use_pip = pip_var.get() pip_opacity = pip_opacity_scale.get() if use_pip else 2 num_pip_videos = int(pip_num_combo.get()) if use_pip else 0 gpu_type = gpu_combo.get() # 临时文件路径 temp_video_path = "temp_processed.mp4" temp_audio_path = "temp_audio.aac" pip_temp_path = "temp_pip.mp4" if use_pip else None background_path = "temp_background.mp4" final_output_path = output_path # 获取原始视频时长和帧率 try: original_clip = VideoFileClip(input_path) original_duration = original_clip.duration original_fps = original_clip.fps original_clip.close() except Exception as e: messagebox.showerror('错误', f'无法打开视频文件: {str(e)}') return False try: # 第一步:创建背景视频 if use_resize: if not create_background_video(background_path, original_duration, 720, 1560, original_fps): messagebox.showerror('错误', '创建背景视频失败!') return False # 第二步:处理视频和音频 if use_video_perturb or use_resize: # 使用OpenCV打开视频 cap = cv2.VideoCapture(input_path) # 获取视频属性 fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 设置目标分辨率 target_width, target_height = 720, 1560 # 创建VideoWriter来写入处理后的视频 fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(temp_video_path, fourcc, fps, (target_width, target_height)) processed_frames = 0 # 主循环:逐帧处理 while True: ret, frame = cap.read() if not ret: break # 读到结尾就退出 # 如果勾选了"调整分辨率",先调整分辨率 if use_resize: frame = resize_with_padding(frame, target_width, target_height) # 如果勾选了"视频扰动",就对当前帧进行处理 if use_video_perturb: frame = add_invisible_overlay(frame, strength) # 写入处理后的帧 out.write(frame) processed_frames += 1 # 更新进度条 progress_var.set(processed_frames / total_frames * 100) root.update_idletasks() # 检查是否取消 if stop_processing: break # 释放资源 cap.release() out.release() if stop_processing: messagebox.showinfo('信息', '处理已取消!') return False # 第三步:处理音频 if use_audio_perturb: # 从原视频提取音频 original_video = VideoFileClip(input_path) original_audio = original_video.audio if original_audio is not None: # 给音频添加水印 processed_audio = add_audio_watermark(original_audio, strength) # 保存处理后的音频到临时文件 processed_audio.write_audiofile(temp_audio_path, logger=None) processed_audio.close() original_video.close() else: # 如果没有勾选音频处理,直接提取原音频 original_video = VideoFileClip(input_path) original_audio = original_video.audio if original_audio is not None: original_audio.write_audiofile(temp_audio_path, logger=None) original_video.close() # 第四步:合并视频和音频 # 如果处理了视频或调整了分辨率,使用处理后的视频,否则使用原视频 video_source = temp_video_path if (use_video_perturb or use_resize) else input_path # 如果有音频文件,合并音频 if os.path.exists(temp_audio_path): # 使用FFmpeg合并音视频 merge_cmd = [ 'ffmpeg', '-i', video_source, '-i', temp_audio_path, '-c:v', 'copy', '-c:a', 'aac', '-map', '0:v:0', '-map', '1:a:0', '-shortest', '-y', final_output_path ] subprocess.run(merge_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) else: # 如果没有音频,直接复制视频 shutil.copy2(video_source, final_output_path) # 第五步:处理元数据(无论是否处理视频音频,只要勾选了就执行) if use_metadata_corrupt: custom_meta = generate_random_metadata() temp_final_path = final_output_path + "_temp.mp4" success = corrupt_metadata(final_output_path, temp_final_path, custom_meta, gpu_type) if success: # 用处理完元数据的文件替换最终文件 if os.path.exists(final_output_path): os.remove(final_output_path) os.rename(temp_final_path, final_output_path) else: return False # 第六步:GAN处理(预留功能) if use_gan: messagebox.showinfo('信息', 'GAN功能是预留选项,在当前版本中未实际生效。') messagebox.showinfo('完成', f'处理完成!\n输出文件已保存至: {final_output_path}') return True except Exception as e: messagebox.showerror('错误', f'处理过程中出现错误: {str(e)}') return False finally: # 清理可能的临时文件 for temp_file in [temp_video_path, temp_audio_path, pip_temp_path, background_path]: if temp_file and os.path.exists(temp_file): try: os.remove(temp_file) except: pass # 重置进度条 progress_var.set(0) # 启用开始按钮 start_button.config(state=tk.NORMAL) stop_processing = False def start_processing(): """开始处理视频""" global stop_processing stop_processing = False start_button.config(state=tk.DISABLED) # 在新线程中处理视频 thread = threading.Thread(target=process_video, daemon=True) thread.start() def stop_processing_func(): """停止处理""" global stop_processing stop_processing = True def browse_input(): """浏览输入文件""" filename = filedialog.askopenfilename( filetypes=[("Video Files", "*.mp4 *.mov *.avi *.mkv"), ("All Files", "*.*")] ) if filename: input_entry.delete(0, tk.END) input_entry.insert(0, filename) def browse_output(): """浏览输出文件""" filename = filedialog.asksaveasfilename( defaultextension=".mp4", filetypes=[("MP4 Files", "*.mp4"), ("All Files", "*.*")] ) if filename: output_entry.delete(0, tk.END) output_entry.insert(0, filename) def toggle_pip_widgets(): """切换画中画相关控件的状态""" state = tk.NORMAL if pip_var.get() else tk.DISABLED pip_num_combo.config(state=state) pip_opacity_scale.config(state=state) def show_gan_info(): """显示GAN功能信息""" if gan_var.get(): messagebox.showinfo('功能说明', '请注意:GAN功能是高级预留功能。\n在当前版本中,它会被一个高级扰动算法模拟,但并非真正的GAN。\n效果依然强大。') # 检测可用GPU detected_gpu = detect_gpu() gpu_options = ["自动检测", "cpu", "nvidia", "amd", "intel"] default_gpu = detected_gpu if detected_gpu != "cpu" else "自动检测" # 创建主窗口 root = tk.Tk() root.title("视频号专版防检测处理工具 v3.0") root.geometry("800x600") # 创建变量 video_var = tk.BooleanVar(value=True) audio_var = tk.BooleanVar(value=True) resize_var = tk.BooleanVar(value=True) metadata_var = tk.BooleanVar(value=True) pip_var = tk.BooleanVar(value=False) gan_var = tk.BooleanVar(value=False) progress_var = tk.DoubleVar(value=0) # 创建界面组件 main_frame = ttk.Frame(root, padding="10") main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # 输入文件选择 ttk.Label(main_frame, text="输入视频文件:").grid(row=0, column=0, sticky=tk.W, pady=5) input_entry = ttk.Entry(main_frame, width=50) input_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Button(main_frame, text="浏览", command=browse_input).grid(row=0, column=2, padx=5, pady=5) # 输出文件选择 ttk.Label(main_frame, text="输出视频文件:").grid(row=1, column=0, sticky=tk.W, pady=5) output_entry = ttk.Entry(main_frame, width=50) output_entry.grid(row=1, column=1, padx=5, pady=5) ttk.Button(main_frame, text="浏览", command=browse_output).grid(row=1, column=2, padx=5, pady=5) # 分隔线 ttk.Separator(main_frame, orient=tk.HORIZONTAL).grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10) # 处理强度 ttk.Label(main_frame, text="处理强度:").grid(row=3, column=0, sticky=tk.W, pady=5) strength_scale = tk.Scale(main_frame, from_=1, to=100, orient=tk.HORIZONTAL, length=400) strength_scale.set(50) strength_scale.grid(row=3, column=1, columnspan=2, sticky=(tk.W, tk.E), padx=5, pady=5) # 分隔线 ttk.Separator(main_frame, orient=tk.HORIZONTAL).grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10) # 处理选项 ttk.Checkbutton(main_frame, text="时空域微扰动 (抗视频指纹 - 核心推荐)", variable=video_var).grid(row=5, column=0, columnspan=3, sticky=tk.W, pady=2) ttk.Checkbutton(main_frame, text="音频指纹污染 (抗音频指纹 - 核心推荐)", variable=audio_var).grid(row=6, column=0, columnspan=3, sticky=tk.W, pady=2) ttk.Checkbutton(main_frame, text="标准化分辨率 (720x1560) + 黑边扰动", variable=resize_var).grid(row=7, column=0, columnspan=3, sticky=tk.W, pady=2) ttk.Checkbutton(main_frame, text="元数据彻底清理与伪造", variable=metadata_var).grid(row=8, column=0, columnspan=3, sticky=tk.W, pady=2) # 画中画选项 pip_frame = ttk.Frame(main_frame) pip_frame.grid(row=9, column=0, columnspan=3, sticky=tk.W, pady=2) ttk.Checkbutton(pip_frame, text="画中画干扰 (从P文件夹随机选择视频)", variable=pip_var, command=toggle_pip_widgets).grid(row=0, column=0, sticky=tk.W) pip_options_frame = ttk.Frame(main_frame) pip_options_frame.grid(row=10, column=0, columnspan=3, sticky=tk.W, pady=2) ttk.Label(pip_options_frame, text="画中画数量:").grid(row=0, column=0, sticky=tk.W, padx=5) pip_num_combo = ttk.Combobox(pip_options_frame, values=[1, 2, 3, 4, 5], state="readonly", width=5) pip_num_combo.set(3) pip_num_combo.grid(row=0, column=1, padx=5) ttk.Label(pip_options_frame, text="透明度 (1-100):").grid(row=0, column=2, sticky=tk.W, padx=5) pip_opacity_scale = tk.Scale(pip_options_frame, from_=1, to=100, orient=tk.HORIZONTAL, length=150) pip_opacity_scale.set(2) pip_opacity_scale.grid(row=0, column=3, padx=5) # 禁用画中画选项 pip_num_combo.config(state=tk.DISABLED) pip_opacity_scale.config(state=tk.DISABLED) # GAN选项 ttk.Checkbutton(main_frame, text="动态GAN对抗性扰动 (预留功能)", variable=gan_var, command=show_gan_info).grid(row=11, column=0, columnspan=3, sticky=tk.W, pady=2) # GPU加速选项 gpu_frame = ttk.Frame(main_frame) gpu_frame.grid(row=12, column=0, columnspan=3, sticky=tk.W, pady=5) ttk.Label(gpu_frame, text="GPU加速:").grid(row=0, column=0, sticky=tk.W) gpu_combo = ttk.Combobox(gpu_frame, values=gpu_options, state="readonly", width=10) gpu_combo.set(default_gpu) gpu_combo.grid(row=0, column=1, padx=5) # 分隔线 ttk.Separator(main_frame, orient=tk.HORIZONTAL).grid(row=13, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10) # 进度条 ttk.Label(main_frame, text="进度:").grid(row=14, column=0, sticky=tk.W, pady=5) progress_bar = ttk.Progressbar(main_frame, variable=progress_var, maximum=100, length=400) progress_bar.grid(row=14, column=1, columnspan=2, sticky=(tk.W, tk.E), padx=5, pady=5) # 按钮 button_frame = ttk.Frame(main_frame) button_frame.grid(row=15, column=0, columnspan=3, pady=10) start_button = ttk.Button(button_frame, text="开始处理", command=start_processing) start_button.pack(side=tk.LEFT, padx=5) ttk.Button(button_frame, text="停止", command=stop_processing_func).pack(side=tk.LEFT, padx=5) ttk.Button(button_frame, text="退出", command=root.quit).pack(side=tk.LEFT, padx=5) # 配置网格权重 root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) main_frame.columnconfigure(1, weight=1) # 运行主循环 root.mainloop() 以上代码在打包时出现问题,请使用Tkinter替代PySimpleGUI代码,通过指定路径解决 MoviePy 导入问题,C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\moviepy_init_.py 这是moviepy路径,给我一个完整的打包操作方案,详细列出所需的所有操作
最新发布
08-21
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值