基于opencv、pyaudio和ffmpeg的录像小程序

本文介绍了一种使用Python实现音视频同步录制的方法,包括利用多线程分别进行视频和音频的录制,随后通过ffmpeg将二者合并成一个视频文件。
部署运行你感兴趣的模型镜像

一、前言

开发前的准备:

在这里插入图片描述


二、过程分析

  1. 采用多线程的方式开始录制画面和录制声音:
    线程一:调用opencv打开摄像头并把画面保存至视频
    线程二:调用pyaudio打开麦克风进行录音

  2. 调用wave模块将音频数据保存至wav文件。

  3. 用ffmpeg将音频和视频合成为一个视频。

1.调用opencv打开摄像头并把画面保存至视频

# 初始化摄像头
self.cap = cv.VideoCapture(1)
if not self.cap.isOpened():
    print('摄像头打开失败')
    
# 初始化 cv.VideoWriter()类,用来保存视频
w, h = int(self.cap.get(cv.CAP_PROP_FRAME_WIDTH)), int(self.cap.get(cv.CAP_PROP_FRAME_HEIGHT))
fourCC = cv.VideoWriter_fourcc('X', 'V', 'I', 'D')
self.out = cv.VideoWriter(filename+'.avi', fourCC, fps=30, frameSize=(w, h))

这里要注意的是在cv.VideoWriter()类实例化的时候,fps设为30。fps指的是保存视频的帧率大小,刚开始我设置为20的时候,发现最后录制的画面时长比音频的时长要长,并且音频和视频是对不上的。如果你们也出现这种状况,尝试修改一下fps的值。

开始录制画面,当按下键盘s的时候结束录制:

while True:
    isOpened,frame = self.cap.read()
    if not isOpened:
        break
    self.out.write(frame)
    cv.imshow('frame',frame)

    if cv.waitKey(1) == ord('s'):
        self.flag_read = False
        break

2.调用pyaudio打开麦克风进行录音


self.NUM_SAMPLES = 1000  # 录音时缓冲区的帧数。
self.my_buf = b''  # 用bytes类型存储音频内容
pa = PyAudio()
self.stream = pa.open(format=paInt16, channels=self.channels, rate=self.framerate, input=True,
                      frames_per_buffer=self.NUM_SAMPLES)
# 参数frames_per_buffer:Specifies the number of frames per buffer.指定每个缓冲区的帧数。

def collect_mp3(self):
    """
    录音
    """
    while self.flag_read:
        string_audio_data = self.stream.read(self.NUM_SAMPLES)
        self.my_buf += string_audio_data
    self.stream.close()

3.调用wave模块将音频数据保存至wav文件。

self.framerate = 32000  # 采样频率
self.channels = 1  # 声道
self.sampWidth = 2  # 量化位数(byte单位)

def save_wave_file(self):
    """
    写入文件
    """
    with wave.open(self.filename + '.wav', 'wb') as wf:
        wf.setnchannels(self.channels)
        wf.setsampwidth(self.sampWidth)
        wf.setframerate(self.framerate)
        wf.writeframes(self.my_buf)
    print('音频写入完成.')

4.用ffmpeg将音频和视频合成为一个视频。

from ffmpy3 import FFmpeg
FFmpeg(inputs={f'{self.filename}.avi':None, f'{self.filename}.wav':None},
               outputs={f'{self.filename}.mp4':'-c:v h264 -c:a ac3'}).run()

ffmpy3是用来驱动ffmpeg程序的,所以电脑上一定要先安装ffmpeg,安装完成之后最好将ffmpeg.exe文件所在路径添加到系统环境变量。
ffmpeg的下载地址在文章开头。


三、完整代码

# Author:FuJLiny
# 优快云 blog homepage:https://blog.youkuaiyun.com/FujLiny
# ------version 1-1,Update time:2020/12/6------
import os
import threading
import time
import wave
from pyaudio import PyAudio,paInt16
import cv2 as cv
from ffmpy3 import FFmpeg


class VCR:
    def __init__(self,filename):
        """
        :param filename: 文件名(不带后缀)
        """
        self.filename = filename
        if os.path.exists(filename+'.mp4'):
            os.remove(filename+'.mp4')

        self.framerate = 32000  # 采样频率
        self.NUM_SAMPLES = 1000  # 录音时缓冲区的帧数。
        self.channels = 1  # 声道
        self.sampWidth = 2  # 量化位数(byte单位)
        self.my_buf = b''  # 用bytes类型存储音频内容
        self.flag_read = True

        self.cap = cv.VideoCapture(1)
        if not self.cap.isOpened():
            print('摄像头打开失败')
        w, h = int(self.cap.get(cv.CAP_PROP_FRAME_WIDTH)), int(self.cap.get(cv.CAP_PROP_FRAME_HEIGHT))
        fourCC = cv.VideoWriter_fourcc('X', 'V', 'I', 'D')
        self.out = cv.VideoWriter(filename+'.avi', fourCC, fps=30, frameSize=(w, h))

        pa = PyAudio()
        self.stream = pa.open(format=paInt16, channels=self.channels, rate=self.framerate, input=True,
                              frames_per_buffer=self.NUM_SAMPLES)
        # 参数frames_per_buffer:Specifies the number of frames per buffer.指定每个缓冲区的帧数。

    def save_wave_file(self):
        """
        写入文件
        """
        with wave.open(self.filename+'.wav','wb') as wf:
            wf.setnchannels(self.channels)
            wf.setsampwidth(self.sampWidth)
            wf.setframerate(self.framerate)
            wf.writeframes(self.my_buf)
        print('音频写入完成.')

    def collect_mp3(self):
        """
        录音
        """
        while self.flag_read:
            string_audio_data = self.stream.read(self.NUM_SAMPLES)
            self.my_buf += string_audio_data
        self.stream.close()

    def collect_mp4(self):
        """
        摄像头画面录制
        :return:
        """
        font = cv.FONT_HERSHEY_COMPLEX
        txt = 'Video start when you press the space key.'
        while True:
            isOpened, frame = self.cap.read()
            if not isOpened:
                break
            cv.putText(frame,txt,(30,150),font,0.8,(0,0,255),1)
            cv.imshow('frame', frame)
            if cv.waitKey(1) == ord(' '):
                break

        print('画面录制开始……')
        threading.Thread(target=self.collect_mp3).start()
        while True:
            isOpened,frame = self.cap.read()
            if not isOpened:
                break
            self.out.write(frame)
            cv.imshow('frame',frame)

            if cv.waitKey(1) == ord('s'):
                # 按下键盘s结束录制
                self.flag_read = False
                break
        self.out.release()
        self.cap.release()
        cv.destroyAllWindows()

    def runMain(self):
        """
        启动位置
        """
        threading.Thread(target=self.collect_mp4).start()
        while self.flag_read:
            time.sleep(1)

        print('准备将音频写入文件……')
        self.save_wave_file()

        print('准备将音频和视频进行合成……')
        # subprocess.Popen(f'ffmpeg -i {self.filename}.avi -i {self.filename}.wav {self.filename}.mp4')
        FFmpeg(inputs={f'{self.filename}.avi':None, f'{self.filename}.wav':None},
               outputs={f'{self.filename}.mp4':'-c:v h264 -c:a ac3'}).run()
        print('合成成功,程序结束。')


if __name__ == '__main__':
    v = VCR(filename='my_audio')
    v.runMain()


参考:
[1]. https://www.cnblogs.com/Neeo/articles/11677715.html

https://www.jianshu.com/p/a401466f3c9d
https://blog.youkuaiyun.com/pythonlaodi/article/details/109222790
https://cloud.tencent.com/developer/news/147840
https://www.cnblogs.com/Neeo/articles/11677715.html
https://ffmpy3.readthedocs.io/en/latest/examples.html
https://baike.baidu.com/item/%E9%87%87%E6%A0%B7%E9%A2%91%E7%8E%87/1494233

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值