heguang 发表于 2024-9-28 16:22

python写的一个录屏录音工具

注册吾爱半年多了,第一次发帖。由于水平太菜了,一直在白嫖别人的工具,前几天看见有人(@william0712 )用python写了一个录屏小工具,想起之前闲来没事的时候我也用gpt写了个类似的,今天正好有空就直接开源出来了。界面十分简单,默认是全屏录屏录音(第一次使用得手动开启电脑声音设置的立体声混音作为输入),勾选不录制扬声器系统声音后只录屏,如果想自定义区域录制要先选择自定义区域录屏,然后再点击开始录制即可。考虑到编程小白的存在,我把代码打包成exe放在文末了,已经尽力在虚拟环境下打包了,但是还是有点大,需要的话自取即可,第一次发帖,如有违规请审核大大提醒修改{:1_889:} 。录音录屏工具

import tkinter as tk
from tkinter import ttk
import tkinter.messagebox as messagebox
import pyautogui
import cv2
import numpy as np
from datetime import datetime
import threading
import pyaudio
import wave
import os
from moviepy.editor import VideoFileClip, AudioFileClip

# 隐藏命令行
import win32console
import win32gui
win = win32console.GetConsoleWindow()
win32gui.ShowWindow(win, 0)

class Popup(tk.Tk):
    def __init__(self):
      super().__init__()
      self.title("设置")
      self.geometry("300x250")
      self.configure(bg="#333333")
      self.create_widgets()
      self.recording_area = None# 初始化录制区域
      self.record_microphone = True# 初始化打开麦克风

    def create_widgets(self):
      self.recording = False
      self.stop_event = threading.Event()# 使用 Event 对象

      self.rec_button = tk.Button(self, text="开始录制", command=self.toggle_recording, bg="#333333", fg="white", borderwidth=2, relief="solid")
      self.rec_button.pack(pady=10)

      self.stop_button = tk.Button(self, text="停止录制", command=self.stop_recording, bg="#333333", fg="white", borderwidth=2, relief="solid", state=tk.DISABLED)
      self.stop_button.pack(pady=5)

      # 区域选择按钮
      self.select_area_button = tk.Button(self, text="选择录制区域", command=self.select_area, bg="#333333", fg="white", borderwidth=2, relief="solid")
      self.select_area_button.pack(pady=10)

      # 扬声器录制选项
      self.mic_checkbox = tk.Checkbutton(self, text="不录制扬声器系统声音", command=self.toggle_microphone, bg="#333333", fg="white", selectcolor="black")
      self.mic_checkbox.pack(pady=10)

    def toggle_microphone(self):
      # 切换麦克风录制的状态
      self.record_microphone = not self.record_microphone

    def select_area(self):
      # 打开一个全屏窗口,允许用户通过鼠标拖动选择区域
      self.selection_window = tk.Toplevel(self)
      self.selection_window.attributes('-fullscreen', True)
      self.selection_window.attributes('-alpha', 0.3)# 半透明
      self.selection_window.config(bg="gray")

      self.canvas = tk.Canvas(self.selection_window, cursor="cross", bg="gray")
      self.canvas.pack(fill="both", expand=True)

      self.rect_id = None
      self.start_x = None
      self.start_y = None

      # 绑定鼠标事件
      self.canvas.bind("<ButtonPress-1>", self.on_mouse_down)
      self.canvas.bind("<B1-Motion>", self.on_mouse_drag)
      self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)

    def on_mouse_down(self, event):
      # 记录起点
      self.start_x = event.x
      self.start_y = event.y
      self.rect_id = self.canvas.create_rectangle(self.start_x, self.start_y, self.start_x, self.start_y, outline='red', width=2)

    def on_mouse_drag(self, event):
      # 动态更新矩形
      self.canvas.coords(self.rect_id, self.start_x, self.start_y, event.x, event.y)

    def on_mouse_up(self, event):
      # 记录终点并计算区域
      end_x = event.x
      end_y = event.y
      self.recording_area = (self.start_x, self.start_y, end_x - self.start_x, end_y - self.start_y)
      self.selection_window.destroy()
      messagebox.showinfo("信息", f"选择的录制区域为:{self.recording_area}")

    def toggle_recording(self):
      if not self.recording:
            self.start_recording()
      else:
            self.stop_recording()

    def start_recording(self):
      self.recording = True
      self.stop_event.clear()# 清除事件状态
      frame_rate = 30
      timestamp = self.get_current_timestamp()
      self.video_filename = f"recorded_video_{timestamp}.mp4"
      self.audio_filename = f"recorded_audio_{timestamp}.wav"

      if self.recording_area is None:
            screen_width, screen_height = pyautogui.size()
            self.recording_area = (0, 0, screen_width, screen_height)# 默认全屏

      codec = cv2.VideoWriter_fourcc(*"mp4v")
      self.video_out = cv2.VideoWriter(self.video_filename, codec, frame_rate, (self.recording_area, self.recording_area))

      # 判断是否需要录制麦克风
      if self.record_microphone:
            # 声音录制线程
            self.audio_thread = threading.Thread(target=self.record_audio, args=(self.audio_filename,))
            self.audio_thread.start()

      # 启动录制线程
      self.recording_thread = threading.Thread(target=self.record_screen)
      self.recording_thread.start()

      self.rec_button.config(text="正在录制", state=tk.DISABLED)
      self.stop_button.config(state=tk.NORMAL)

    def record_screen(self):
      while not self.stop_event.is_set():# 检查事件状态
            img = pyautogui.screenshot(region=self.recording_area)# 录制自定义区域
            frame = np.array(img)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            self.video_out.write(frame)

      self.video_out.release()
      print("视频录制结束")

    def record_audio(self, filename):
      chunk = 1024
      sample_format = pyaudio.paInt16
      channels = 2
      fs = 44100# 采样频率

      p = pyaudio.PyAudio()

      # 打开麦克风输入流
      stream = p.open(format=sample_format,
                        channels=channels,
                        rate=fs,
                        input=True,
                        frames_per_buffer=chunk)

      frames = []

      while not self.stop_event.is_set():# 检查事件状态
            data = stream.read(chunk)
            frames.append(data)

      stream.stop_stream()
      stream.close()
      p.terminate()

      # 保存音频到 wav 文件
      with wave.open(filename, 'wb') as wf:
            wf.setnchannels(channels)
            wf.setsampwidth(p.get_sample_size(sample_format))
            wf.setframerate(fs)
            wf.writeframes(b''.join(frames))

      print("录音结束")

    def stop_recording(self):
      self.recording = False
      self.stop_event.set()# 设定事件,结束录制

      if self.record_microphone:
            self.audio_thread.join()# 等待音频线程结束

      if os.path.isfile('merged_video.mp4'):
            messagebox.showinfo("提示", "合并视频文件已保存至当前目录文件夹,想重新录制请删除原文件后重试!")
            # 更新按钮状态
            self.rec_button.config(text="请删除原文件后再开始录制", state=tk.NORMAL)
            self.stop_button.config(state=tk.DISABLED)
      else:
            # 合成音视频
            self.merge_audio_video()

    def merge_audio_video(self):
      merge_file = 'merged_video.mp4'

      video_clip = VideoFileClip(self.video_filename)

      if self.record_microphone:
            audio_clip = AudioFileClip(self.audio_filename)
            final_clip = video_clip.set_audio(audio_clip)
      else:
            final_clip = video_clip# 如果没有录音,只保存视频

      final_clip.write_videofile(merge_file, codec='libx264', audio_codec="aac")

      # 删除录制的视频文件和音频文件
      os.remove(self.video_filename)
      if self.record_microphone:
            os.remove(self.audio_filename)

      print("音视频合成完成,存储为", merge_file)
      # 更新按钮状态
      self.rec_button.config(text="开始录制", state=tk.NORMAL)
      self.stop_button.config(state=tk.DISABLED)

    def get_current_timestamp(self):
      return datetime.now().strftime("%Y%m%d_%H%M%S")

if __name__ == "__main__":
    popup = Popup()
    popup.mainloop()

dzwxj 发表于 2024-11-11 10:42

本帖最后由 dzwxj 于 2024-11-11 10:52 编辑

测试了一下,才录制3分钟看了一下文件(应该是录制过程中文件(默认在当前目录下))就达250MB左右,这会影响录制的流畅性及最后存储收尾时的稳定性,弄不好最后停止会软件崩溃。一般用其它软件录制一小时最终的视频文件也就才一两百MB左右,最大也就一个GB(选择4K超清录制模式)。
另一个问题是,就录了3分钟,点停止录制,结果卡住了,半天停止不下来没法完成最终录制文件的写入,最后录制生成的最终文件打开看结束也就定格在“停止录制”界面死机这种状态下,哈哈。这说明在最后收尾时,对最终文件的写入完成存在一些有待优化的空间。因为我用的录制软件太多了,但基本上是点了停止立马结束。总之,PYTHON这个呢功能是强大,能做的事情也多,但真正在性能上达到用户的要求还是有一定差距的。毕竟这一部分压缩算法这些恰恰是它的弱项。虽然PYTHON的底层也是用别人的各种库,但毕竟是脚本语言,加上死丑的TK和低效率和差的稳定性,导致了一些不尽人意的设计。

heguang 发表于 2024-9-29 13:17

链接好像没加进来,补个链接:https://wwjg.lanzouo.com/ijYNK2b2g8wh
密码:52pj

fast123 发表于 2024-9-29 19:07

拿走了感谢

wasm2023 发表于 2024-9-30 09:56

感谢分享

aodiming 发表于 2024-9-30 20:19

想入门,一直没有这种源代码参考,感谢分享

xiaolinge566 发表于 2024-10-1 11:42

感谢分享。

heguang 发表于 2024-10-4 13:58

此问题目前已解决,有时间再更新一下帖子吧

本帖最后由 heguang 于 2024-10-4 14:36 编辑

今天才发现好像录制的视频音画不同步,有没有大神帮忙修复下

shuguang2121 发表于 2024-10-4 17:26

感谢分享

weiloveyuan 发表于 2024-10-8 11:04

刚好需要这款软件,感谢分享,谢谢

piazini 发表于 2024-10-9 22:33

都是大佬,啥工具都有
页: [1] 2 3 4 5
查看完整版本: python写的一个录屏录音工具