You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Zero 2W单独录音频正常,音视频同录时无音频

问题:树莓派Zero 2W音视频录制整合后无音频输出

我使用树莓派Zero 2W连接了Adafruit MEMS麦克风和摄像头,单独测试音频录制的Python程序功能完全正常,代码如下:

import subprocess
import threading
import os

audio_process = None
stop_recording_flag = False
audio_filename = "test.wav"

def record_audio():
    global audio_process, stop_recording_flag

    env = os.environ.copy()
    env["HOME"] = os.path.expanduser("~")

    print("Recording... Type 'stop' and press Enter to stop.")

    audio_process = subprocess.Popen([
        "arecord", "-D", "dmic_sv", "-c", "2", "-r", "48000",
        "-f", "S32_LE", "-t", "wav", audio_filename
    ], env=env)

    # Wait until user types 'stop'
    while not stop_recording_flag and audio_process.poll() is None:
        pass

    if audio_process.poll() is None:
        print("Stopping recording...")
        audio_process.terminate()
        try:
            audio_process.wait(timeout=5)
        except subprocess.TimeoutExpired:
            audio_process.kill()

    print(f"Recording saved to {audio_filename}")

def monitor_input():
    global stop_recording_flag
    while True:
        command = input().strip().lower()
        if command == "stop":
            stop_recording_flag = True
            break

if __name__ == "__main__":
    t1 = threading.Thread(target=record_audio)
    t2 = threading.Thread(target=monitor_input)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

但将该音频录制逻辑整合到同时录制音视频并混流的主程序后,视频录制正常,但audio.wav文件及最终生成的视频中均无音频输出。已确认麦克风功能正常,混流逻辑也无问题,可以确定问题出在音频录制的线程启动方式上,以下是简化后的主程序代码:

import time
import subprocess
import threading
from picamera2 import Picamera2
from PIL import Image, ImageDraw
import RPi.GPIO as GPIO

video_selected_index = 0
is_recording = False
framerate = 30
video_filename = "/home/pi/video.h264"
audio_wav_filename = "/home/pi/audio.wav"
final_filename = ""
picam = None
audio_process = None
audio_thread = None
video_thread = None
font = None  # 需根据实际场景初始化字体对象
display = None  # 需根据实际场景初始化显示屏对象
video_resolutions = []  # 需提前定义分辨率选项列表,格式为[(标签, 配置), ...]

def recording_ui_updater():
    # 需补充UI状态更新逻辑
    pass

def record_video(config):
    # 需补充视频录制核心逻辑
    pass

def wait_for_button_release(pin):
    while GPIO.input(pin) == GPIO.LOW:
        time.sleep(0.01)

def recording_status(status_text):
    # 需补充录制状态显示逻辑
    pass

def record_audio():
    global audio_process, is_recording

    try:
        print("  [record_audio] Starting audio capture, Sir.")
        env = os.environ.copy()
        env["HOME"] = os.path.expanduser("~")

        audio_process = subprocess.Popen([
            "arecord", "-D", "dmic_sv", "-c", "2", "-r", "48000",
            "-f", "S32_LE", "-t", "wav", audio_wav_filename
        ], env=env)

        # Wait for is_recording to turn False
        while is_recording:
            time.sleep(0.1)

        if audio_process.poll() is None:
            print("  [record_audio] Terminating arecord…")
            audio_process.terminate()
            try:
                audio_process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                audio_process.kill()

        print(f"  [record_audio] Audio saved to {audio_wav_filename}, Sir.")

    except Exception as e:
        print(f"  [record_audio] Exception, Sir: {e}")

def start_recording(config):
    """
    Launch audio + video threads (non-daemon), with a slight stagger.
    """
    global is_recording, audio_thread, video_thread

    is_recording = True

    # Start UI updater thread (could remain daemon)
    threading.Thread(target=recording_ui_updater, daemon=True).start()

    # Create *non-daemon* threads for audio & video so they run fully
    audio_thread = threading.Thread(target=record_audio, daemon=False)
    video_thread = threading.Thread(target=record_video, args=(config,), daemon=False)

    # Start audio first, give it time to initialize DMIC
    audio_thread.start()
    time.sleep(0.1)

    # Now start video capture
    video_thread.start()

def stop_recording():
    """
    Signal both threads to finish, then join.
    """
    global is_recording

    is_recording = False
    print("  [stop_recording] Signaled threads to stop.")
    recording_status("Muxing...")

    if audio_thread:
        audio_thread.join()

    # Give time for OS to flush file buffers
    time.sleep(0.5)  # Crucial

    if video_thread:
        print("  [stop_recording] Joining video thread…")
        video_thread.join()

    print("  [stop_recording] Threads joined, proceeding to mux.")
    mux_audio_video()

def show_take_video_menu():
    global video_selected_index, is_recording, picam
    try:
        picam = Picamera2()
        picam.configure(picam.create_still_configuration())
        picam.start()
        time.sleep(2)  # Camera warm-up
    except Exception as e:
        print(f"Camera initialization failed: {e}")
        return

    while True:
        if not is_recording:
            # Draw resolution menu
            img = Image.new("RGB", (160, 80), "black")
            draw = ImageDraw.Draw(img)
            title = "Take Video"
            title_width = draw.textlength(title, font=font)
            draw.text(((160 - title_width) // 2, 2), title, font=font, fill="red")

            for i, (label, _) in enumerate(video_resolutions):
                prefix = "> " if i == video_selected_index else "  "
                draw.text((10, 18 + i * 14), prefix + label, font=font, fill="red")
            display.display(img)

        # Button controls
        if GPIO.input(21) == GPIO.LOW:  # UP
            wait_for_button_release(21)
            video_selected_index = (video_selected_index - 1) % len(video_resolutions)

        elif GPIO.input(12) == GPIO.LOW:  # DOWN
            wait_for_button_release(12)
            video_selected_index = (video_selected_index + 1) % len(video_resolutions)

        elif GPIO.input(16) == GPIO.LOW:  # SELECT
            wait_for_button_release(16)
            label, config = video_resolutions[video_selected_index]

            if is_recording:
                stop_recording()
                continue

            if label.lower() == "return":
                if is_recording:
                    stop_recording()
                print("Exiting video menu.")
                picam.close()
                return

            if config:
                start_recording(config)

        time.sleep(0.1)  # Input debounce delay

def mux_audio_video():
    global final_filename, framerate
    timestamp = time.strftime("%Y%m%d_%H%M%S")
    final_filename = f"/home/pi/Videos/recording_{timestamp}.mp4"
    subprocess.run([
        "ffmpeg", "-y",
        "-framerate", str(framerate),
        "-i", video_filename,
        "-i", audio_wav_filename,
        "-metadata:s:v", "rotate=270",
        "-c:v", "copy",
        "-c:a", "aac",
        "-shortest", final_filename
    ], check=True)
    print(f"Muxed to {final_filename}")

内容的提问来源于stack exchange,提问作者symmetrical pattern with teal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:24:58