应用市场上录屏工具的原理很好理解,一是屏幕,二是声音。从这个角度出发,我们就可以对屏幕和声音同步来录制,最后在将音频和视频合并在一起,最后我们就得到了我们录屏的视频。

 为了使音频和视频同步,这里采用双线程同步进行,同时启动,同时结束。

 为了更好的理解,做了详细的注释。

导包

import wave
import pyaudio
import cv2
import moviepy
import threading
import _thread
import numpy as np
from time import sleep
from PIL import ImageGrab
from datetime import datetime
from moviepy.editor import AudioFileClip,VideoFileClip

import warnings
warnings.filterwarnings("ignore")

音频的录制

 音频的录制采用的是 pyaudio 库来启用麦克风记录声音并保存到本地。

def record_audio(self):
        #创建一个pyaudio对象
        recordAudio = pyaudio.PyAudio()
        #创建一个输入流stream
        stream = recordAudio.open(format = pyaudio.paInt16,#使用量化位数,16位
                channels = 2,#双声道数
                rate = 44100,#采样频率
                input = True,#确定是输入流
                frames_per_buffer = 128#指定每个数据帧数
                )
        
        waveFile = wave.open(self.audio_filename,'wb')
        #音频通道数
        waveFile.setnchannels(2)
        #量化位数
        waveFile.setsampwidth(recordAudio.get_sample_size(pyaudio.paInt16))
        #采样频率
        waveFile.setframerate(44100)
        #录制,不断写入
        while self.recording:
            waveFile.writeframes(stream.read(128))
        
        waveFile.close()
        #停止输入
        stream.stop_stream()
        #关闭输入流
        stream.close()
        recordAudio.terminate()
        pass

视频的录制

 视屏的录制采用的是不断获取当前屏幕的截图,然后利用 opencv 写入到视频文件中。

def video_record(self):
        #获取屏幕
        screen = ImageGrab.grab()
        #转换RGB
        video = cv2.VideoWriter(self.video_record_filename,cv2.VideoWriter_fourcc(*'XVID'),20,screen.size)
        #录制
        while self.recording:
            #截取屏幕
            screen = ImageGrab.grab()
            screen = cv2.cvtColor(np.array(screen),cv2.COLOR_RGB2BGR)
            #写入到本地文件
            video.write(screen)
        print(datetime.now())
        #释放
        video.release()
        pass

主程序

def run(self):
        print("3秒后开始录制,输入quit结束")
        sleep(3)
        #文件命名为当前时间
        self.now = str(datetime.now())[:19].replace(':','_').replace('-','_').replace(' ','_')
        #音频
        self.audio_filename = "{}.wav".format(self.now)
        #视频
        self.video_record_filename = "{}_video.avi".format(self.now)
        #最终的视频
        self.video_filename = "{}.mp4".format(self.now)
        #开启两个线程
        t1 = threading.Thread(target = self.record_audio)
        t2 = threading.Thread(target = self.video_record)
        
        for t in [t1,t2]:
            t.start()
        while True:
            if(input() == 'quit'):
                break
        #两个线程同时结束
        self.recording = False
        for t in [t1,t2]:
            t.join()
        
        audio = AudioFileClip(self.audio_filename) #moviepy读取视频
        video = VideoFileClip(self.video_record_filename)#moviepy读取音频
        totalVideo = video.set_audio(audio)#音频附加到视频上
        #编码.mp4  帧率25
        totalVideo.write_videofile(self.video_filename,codec = "libx264",fps = 25)
        pass

 当然了,也可以用PyQt实现图形化界面,真正的实现录屏软件。

收获 —— 多线程

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
  • 程序的运行速度可能加快。
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

例如

import time
import threading

def tstart():
    time.sleep(0.5)
    print(" running....")

if __name__ == '__main__':
    #创建线程
    t1 = threading.Thread(target = tstart)
    t2 = threading.Thread(target = tstart)
    #开启线程
    for t in [t1,t2]:
        t.start()
	#join的原理就是依次检验线程池中的线程是否结束
	#没有结束就阻塞直到线程结束
	#如果结束则跳转执行下一个线程的join函数。
    for t in [t1,t2]:
        t.join()
    print("This is main function")