Python中基于随机状态的音视频重排解密失效问题求助
Python中基于随机状态的音视频重排解密失效问题求助
嘿,我仔细看了你的加密和解密代码,发现几个导致无法正确还原音视频顺序的核心问题,咱们一步步来拆解和解决:
问题根源梳理
随机状态保存时机完全错误
你在整个加密流程结束后才保存随机状态,但加密过程中调用了两次random.shuffle(一次处理音频文件名列表,一次处理视频帧),这会持续改变随机状态。等你保存时,状态已经是两次shuffle后的结果,解密时加载这个状态根本没法还原最初的shuffle顺序。音频处理逻辑前后不一致
加密时你是对音频文件名字符串列表做shuffle,而解密时却直接对音频数据块列表生成索引,两者的shuffle对象完全不匹配,自然没法对应上原顺序。视频帧解密逻辑缺失
你的解密代码里只打印了帧的shuffle索引,但完全没写根据索引还原原帧顺序的逻辑,这直接导致视频帧根本没被还原。重复设置随机种子冲突
加密和解密时,你既加载保存的随机状态,又调用random.seed(secret_word),这会直接覆盖加载的状态,导致shuffle顺序完全不一致。
修正后的解决方案
我建议放弃保存随机状态的方案,转而保存shuffle后的索引序列——这种方式更可靠,避免了Python版本、环境对随机状态序列化的影响,逻辑也更直观。
修正后的加密代码
import os import random import pickle import numpy as np from moviepy import VideoFileClip, AudioFileClip, ImageSequenceClip import librosa import soundfile as sf import shutil # 保存音频和视频的shuffle索引 def save_shuffle_indices(indices_dict, filename='shuffle_indices.pkl'): with open(filename, 'wb') as f: pickle.dump(indices_dict, f) def extract_and_reorder_audio_video(video_file, secret_word, chunk_duration=1, output_folder='output_videos'): try: os.makedirs(output_folder, exist_ok=True) base_name = os.path.splitext(os.path.basename(video_file))[0] output_video = os.path.join(output_folder, f"{base_name}_reordered.mp4") output_audio_temp = os.path.join(output_folder, f"{base_name}_temp_audio.wav") # 加载视频和原始音频 video_clip = VideoFileClip(video_file) audio_clip = video_clip.audio audio_file = f"{base_name}_original.wav" audio_clip.write_audiofile(audio_file) # 处理音频:切分块并生成shuffle索引 y, sr = librosa.load(audio_file, sr=None) chunk_samples = int(chunk_duration * sr) chunks = [y[i:i + chunk_samples] for i in range(0, len(y), chunk_samples)] random.seed(secret_word) audio_shuffle_indices = list(range(len(chunks))) random.shuffle(audio_shuffle_indices) # 按索引打乱音频块 shuffled_audio = [chunks[i] for i in audio_shuffle_indices] final_shuffled_audio = np.concatenate(shuffled_audio) sf.write(output_audio_temp, final_shuffled_audio, sr) # 处理视频帧:生成shuffle索引并打乱 frames = [frame for frame in video_clip.iter_frames(fps=video_clip.fps, dtype='uint8')] video_shuffle_indices = list(range(len(frames))) random.shuffle(video_shuffle_indices) shuffled_frames = [frames[i] for i in video_shuffle_indices] # 生成重排后的视频 reordered_video = ImageSequenceClip(shuffled_frames, fps=video_clip.fps) reordered_audio = AudioFileClip(output_audio_temp) reordered_video.audio = reordered_audio reordered_video.write_videofile(output_video, codec='libx264') print(f"加密后的视频已保存到: {output_video}") # 保存关键索引和参数 save_shuffle_indices({ 'audio_indices': audio_shuffle_indices, 'video_indices': video_shuffle_indices, 'chunk_duration': chunk_duration }) except Exception as e: print(f"处理视频时出错: {e}") finally: # 清理临时文件 try: for temp_file in [audio_file, output_audio_temp]: if os.path.exists(temp_file): os.remove(temp_file) print("临时文件已清理") except Exception as cleanup_err: print(f"清理临时文件出错: {cleanup_err}") def process_folder(folder_path, secret_word, chunk_duration=1): video_files = [f for f in os.listdir(folder_path) if f.endswith(('.mp4', '.mov', '.avi', '.mkv'))] for video_file in video_files: full_path = os.path.join(folder_path, video_file) print(f"正在处理: {full_path}") extract_and_reorder_audio_video(full_path, secret_word, chunk_duration) # 使用示例 process_folder('videos', 'password')
修正后的解密代码
import os import pickle import numpy as np import librosa import soundfile as sf from moviepy import VideoFileClip, ImageSequenceClip, AudioFileClip # 加载保存的shuffle索引 def load_shuffle_indices(filename='shuffle_indices.pkl'): try: with open(filename, 'rb') as f: return pickle.load(f) except FileNotFoundError: print("错误:未找到shuffle索引文件,无法解密") return None def decrypt_audio_video(file_path, secret_word, output_folder='output_decrypted'): indices_dict = load_shuffle_indices() if not indices_dict: return try: os.makedirs(output_folder, exist_ok=True) base_name = os.path.splitext(os.path.basename(file_path))[0].replace("_reordered", "") output_video = os.path.join(output_folder, f"{base_name}_original.mp4") output_audio_temp = os.path.join(output_folder, f"{base_name}_temp_audio.wav") # 加载加密后的视频 video_clip = VideoFileClip(file_path) if video_clip.audio is None: raise ValueError("该视频文件不包含音频") # 解密音频 video_clip.audio.write_audiofile(output_audio_temp) y, sr = librosa.load(output_audio_temp, sr=None) chunk_samples = int(indices_dict['chunk_duration'] * sr) chunks = [y[i:i + chunk_samples] for i in range(0, len(y), chunk_samples)] # 根据索引还原原音频顺序 audio_indices = indices_dict['audio_indices'] original_audio_chunks = [None] * len(chunks) for original_idx, shuffled_idx in enumerate(audio_indices): original_audio_chunks[shuffled_idx] = chunks[original_idx] final_original_audio = np.concatenate(original_audio_chunks) sf.write(output_audio_temp, final_original_audio, sr) # 解密视频帧 frames = [frame for frame in video_clip.iter_frames(fps=video_clip.fps, dtype='uint8')] video_indices = indices_dict['video_indices'] original_frames = [None] * len(frames) for original_idx, shuffled_idx in enumerate(video_indices): original_frames[shuffled_idx] = frames[original_idx] # 生成还原后的视频 original_video = ImageSequenceClip(original_frames, fps=video_clip.fps) original_audio = AudioFileClip(output_audio_temp) original_video.audio = original_audio original_video.write_videofile(output_video, codec='libx264') print(f"解密后的视频已保存到: {output_video}") except Exception as e: print(f"解密视频时出错: {e}") finally: # 清理临时文件 if os.path.exists(output_audio_temp): os.remove(output_audio_temp) print("临时文件已清理") # 使用示例 decrypt_audio_video('output_videos/test_reordered.mp4', 'password')
关键改进说明
- 用索引序列替代随机状态:直接保存shuffle后的索引列表,避免了随机状态序列化的兼容性问题,还原逻辑更清晰。
- 统一音频处理逻辑:加密和解密都针对音频数据块的索引操作,不再涉及文件名的shuffle,逻辑完全对应。
- 完善视频帧还原逻辑:根据保存的视频索引,正确将打乱的帧还原为原始顺序。
- 移除冗余的种子设置:只在加密时设置一次种子生成索引,解密时直接使用保存的索引,避免状态冲突。
你可以试试这套修正后的代码,应该能完美还原音视频的原始顺序了!
备注:内容来源于stack exchange,提问作者Hegel Pedroza
相关产品推荐
相关产品推荐

