You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中基于随机状态的音视频重排解密失效问题求助

Python中基于随机状态的音视频重排解密失效问题求助

嘿,我仔细看了你的加密和解密代码,发现几个导致无法正确还原音视频顺序的核心问题,咱们一步步来拆解和解决:

问题根源梳理

  1. 随机状态保存时机完全错误
    你在整个加密流程结束后才保存随机状态,但加密过程中调用了两次random.shuffle(一次处理音频文件名列表,一次处理视频帧),这会持续改变随机状态。等你保存时,状态已经是两次shuffle后的结果,解密时加载这个状态根本没法还原最初的shuffle顺序。

  2. 音频处理逻辑前后不一致
    加密时你是对音频文件名字符串列表做shuffle,而解密时却直接对音频数据块列表生成索引,两者的shuffle对象完全不匹配,自然没法对应上原顺序。

  3. 视频帧解密逻辑缺失
    你的解密代码里只打印了帧的shuffle索引,但完全没写根据索引还原原帧顺序的逻辑,这直接导致视频帧根本没被还原。

  4. 重复设置随机种子冲突
    加密和解密时,你既加载保存的随机状态,又调用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')

关键改进说明

  1. 用索引序列替代随机状态:直接保存shuffle后的索引列表,避免了随机状态序列化的兼容性问题,还原逻辑更清晰。
  2. 统一音频处理逻辑:加密和解密都针对音频数据块的索引操作,不再涉及文件名的shuffle,逻辑完全对应。
  3. 完善视频帧还原逻辑:根据保存的视频索引,正确将打乱的帧还原为原始顺序。
  4. 移除冗余的种子设置:只在加密时设置一次种子生成索引,解密时直接使用保存的索引,避免状态冲突。

你可以试试这套修正后的代码,应该能完美还原音视频的原始顺序了!

备注:内容来源于stack exchange,提问作者Hegel Pedroza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 03:43:02