1. 使用 nanopc-T4 开发板采集音频

使用开发板采集音频时,总是报错,通过查阅很多资料后,逐渐有了一些头绪。

  • 使用 arecord -l 命令可以查看当前系统的录音设备。

由此可以看出,当前系统有两个 USB Audio 设备,分别为 Tyless 外置录音和 C920 摄像头自带的录音设备。

root@NanoPC-T4:/home/pi/projects/nanopc/nanopc2jetlinks4mqtt# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: realtekrt5651co [realtek,rt5651-codec], device 0: ff880000.i2s-rt5651-aif1 rt5651-aif1-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 3: Tyless [Tyless], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 4: C920 [HD Pro Webcam C920], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
  • 使用指定声卡录音
root@NanoPC-T4:/home/pi/projects/nanopc/nanopc2jetlinks4mqtt# sudo arecord -D hw:4 -d 40 test.wav -r16000 -fS16_LE -c 2
Recording WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono

-D 表示指定设备,hw:x 表示第x个设备(使用命令 arecord -l 查看)

-d 表示时间,单位为秒

'test.wav' 为录音保存的文件名

-r 表示设置频率

-f 为设置格式

-c 表示通道数

2. 使用 Tyless 录制声音

使用 arecord -l 查看 tyless 的设备号,input_device_index=3
设置频率 rate 为48000Hz
设置通道数 CHANNELS 为 1

具体代码如下(测试通过):

# name:008.py
#录制音频
import wave
import pyaudio

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
# RATE = 44100
RATE = 48000
#RATE = 22050
RECORD_SECONDS =30
p = pyaudio.PyAudio()
#i=0
while True:
    #i=i+1
    # 数据流
    stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True,input_device_index=3, frames_per_buffer=CHUNK)
    print("开始录音!")
    frames = []
    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK,exception_on_overflow = False)
        frames.append(data)
    print("录音完毕!")
    # 停止数据流
    stream.stop_stream()
    stream.close()
    # 关闭PyAudio
    #p.terminate()#不能这样操作,否则会出现不能循环的现
    # 写入录音文件
    wf = wave.open('011.wav', 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()
    print('音频数据写入完成')
    break;

具体代码 :https://gitee.com/qiaoyukeji/nanopc2jetlinks4mqtt/blob/master/test_005_audio/008.py

3. 使用 ffrmpeg 将实时视频与音频合并并推流到 rtmp 服务器中

ffmpeg \
-f alsa -ac 2 -i hw:4,0 -r 48000 \
-f v4l2 -r 10 -i /dev/video0 \
-c:v libx264 -s 640x480 -pix_fmt yuv420p -preset ultrafast -g 20 -b:v 2500k \
-c:a aac -ar 44100 \
-threads 0 -bufsize 512k \
-f flv rtmp://iot.gitnote.cn/live/test &> stream.log

-f fmt 指定格式(音频或视频格式)

-ac channels 设置声道数

-i filename 指定输入文件名,在linux下当然也能指定:0.0(屏幕录制)或摄像头

-r rate 桢速率(fps)

-vcodec codec 强制使用codec编解码方式(copy to copy stream)

-acodec codec 指定音频编码(copy to copy stream)

-pix_fmt format 设置像素格式,“列表”作为参数显示所有支持的像素格式

-g int 设置图像组大小

-b 指定比特率(bits/s),似乎ffmpeg是自动VBR的,指定了就大概是平均比特率

-ar rate 设置音频采样率 (单位:Hz)

具体参数含义见:https://www.scivision.dev/youtube-live-ffmpeg-livestream/

4. 成功实现opencv采集图像与音频合并推送到rtmp

  • 图像使用opencv调用摄像头采集并处理

  • 音频使用 alsa 在 ffmpeg 命令行中采集

  • 然后合并推送远程rtmp服务器中

相关代码见:https://gitee.com/qiaoyukeji/nanopc2jetlinks4mqtt/blob/master/test_005_audio/rtmp_001.py

# 本代码实现 opencv 采集视频并使用ffmpeg与音频audio合并推送到远程 rtmp 服务器中 
# rtmp_001.py

# 需先自行安装FFmpeg,并添加环境变量
import cv2
import subprocess
import datetime
import numpy as np
from PIL import Image, ImageDraw, ImageFont

# RTMP服务器地址
# rtmp = r'rtmp://156756.livepush.myqcloud.com/live/test'
# rtmp = r'rtmp://172.17.14.191/live/test'
rtmp = r'rtmp://iot.gitnote.cn/live/test'
# 读取视频并获取属性
cap = cv2.VideoCapture(0)

cap.set(3, 640) # set video widht
cap.set(4, 480) # set video height
size = (int(640), int(480))
sizeStr = str(size[0]) + 'x' + str(size[1])
command = ['ffmpeg',
    '-y',  # -y	覆盖已有文件
    "-thread_queue_size","102400", # 封装队列大小
    ########### 音频采集相关参数
    '-f', 'alsa', # -f fmt	指定格式(音频或视频格式)
    '-ac', '2', # -ac channels	设置声道数
    '-i', 'hw:3,0', # -i filename	指定输入文件名,在linux下当然也能指定:0.0(屏幕录制)或摄像头
    ############ 视频处理相关参数
    # '-f', 'v4l2',
    '-f', 'rawvideo',  # -f fmt	指定格式(音频或视频格式)
    '-vcodec','rawvideo', # -vcodec codec	强制使用codec编解码方式
    '-pix_fmt', 'bgr24', # -pix_fmt format  设置像素格式,“列表”作为参数显示所有支持的像素格式
    '-s', sizeStr, # -s size	分辨率
    '-r', '25', #  -r rate	桢速率(fps)
    '-i', '-',
    '-c:v', 'libx264',
    '-pix_fmt', 'yuv420p',
    '-preset', 'ultrafast',
    '-b:v','2000k',
    '-c:a', 'aac', # 设置音频格式
    '-ar', '44100',  # -ar rate	设置音频采样率 (单位:Hz)
    "-threads","2",
    "-bufsize","1024k", 
    '-f', 'flv',

    rtmp]
pipe = subprocess.Popen(command, shell=False, stdin=subprocess.PIPE)

font = cv2.FONT_ITALIC   # 字体
fourcc = cv2.VideoWriter_fourcc(*'XVID')  #定义编解码器并创建VideoWriter对象,即输入四个字符代码即可得到对应的视频编码器(XVID编码器)
out = cv2.VideoWriter('video1.avi', fourcc, 20.0, (640,480))  #参数:保存文件名,编码器,帧率,视频宽高


# 图片帧添加文字函数
def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    if (isinstance(img, np.ndarray)):  # 判断是否OpenCV图片类型
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    # 创建一个可以在给定图像上绘图的对象
    draw = ImageDraw.Draw(img)
    # 字体的格式
    fontStyle = ImageFont.truetype(
        "simsun.ttc", textSize, encoding="utf-8")
    # 绘制文本
    draw.text((left, top), text, textColor, font=fontStyle)
    # 转换回OpenCV格式
    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)


while cap.isOpened():
    success, frame = cap.read()
    cv2.putText(frame,(datetime.datetime.utcnow() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), (15,40),font , 1, (255,255,255), 2) 
    # cv2.putText(frame,'安徽农业大学智慧养殖平台:HF-001 ', (15,400),font , 1, (255,255,255), 2) 
    # frame=cv2ImgAddText(frame,"安徽农业大学智慧养殖平台:HF-XX-001",15,50,(255,255,255),24)
    if success:
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        pipe.stdin.write(frame.tostring())
        out.write(frame)

cap.release()
pipe.terminate()
cv2.destroyAllWindows()