一、前言
开发前的准备:
- 需要用到的第三方库:opencv-python、wave、pyaudio、ffmpy3(这4个库都可以通过pip工具直接安装)
- 额外的工具(用来合成音频和视频):ffmpeg
ffmpeg下载下载地址:官网:https://www.ffmpeg.org/
Github地址:https://github.com/FFmpeg/FFmpeg
百度网盘链接:https://pan.baidu.com/s/1UBcoXy6v3XG8oz0GuMKd8w 提取码:90ow[1]

二、过程分析
-
采用多线程的方式开始录制画面和录制声音:
线程一:调用opencv打开摄像头并把画面保存至视频
线程二:调用pyaudio打开麦克风进行录音 -
调用wave模块将音频数据保存至wav文件。
-
用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
本文介绍了一种使用Python实现音视频同步录制的方法,包括利用多线程分别进行视频和音频的录制,随后通过ffmpeg将二者合并成一个视频文件。
1306

被折叠的 条评论
为什么被折叠?



