繁体   English   中英

为什么我的代码无法保存从网络摄像头捕获的帧的视频文件,但我可以将帧保存为图像文件就好了?

[英]Why my code fails to save video files of frames capture from a webcam but I can save the frames as image files just fine?

我正在尝试开发 Python 脚本,它可以从网络摄像头捕获和记录帧,还可以从麦克风记录音频几秒钟,并重复直到预定时间停止。 来自网络摄像头的帧可以保存为 jpg 文件就好了。 音频也可以毫无问题地保存为 wav 文件。 但视频文件无法打开并报错“此文件无法播放。这可能是因为文件类型不受支持、文件扩展名不正确或文件已损坏。” 我使用 OpenCV 获取帧并记录视频和图像文件。 我已经在我的电脑(Windows 10)上安装了 ffmpeg,运行我的代码时没有出现异常错误。

下面是我制作的脚本。 该程序设置为运行 runningDur = 12 秒。 每个视频文件 (.mp4) 应每 5 秒保存一次,持续时间为 5 秒 (videoSaveIntv)。 每 4 秒 (frameSaveIntv) 将一帧保存为图像文件 (.jpg)。 音频文件将每 5 秒 (audioSaveIntv) 保存一次,持续时间为 4 秒 (audirorecdur)。

import numpy as np
import cv2 as cv
from datetime import time, datetime, timedelta
import sounddevice as sd
from scipy.io.wavfile import write as audioWrite
from threading import Thread
import traceback


cap = cv.VideoCapture(0) # use this line for testing with local camera (webcam, etc.)

# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'mp4v')
fps = 20.0
#frameSize = (640, 480)
frameSize = (cv.CAP_PROP_FRAME_WIDTH, cv.CAP_PROP_FRAME_HEIGHT)
# Define parameters for audio recording
audirorecdur = 4
fs= 44100
sd.default.samplerate = fs
sd.default.channels = 1
# flag to trigger video recording
flag1 = True
# flag to trigger frame capture
flag2 = True 
# flag to trigger audio recording
flag3 = True
# startTime1 is to help controlling when we will save a frame as an image file
startTime1 = datetime.now()
# startTime2 is to help controlling how long this script will run
startTime2 = startTime1
# startTime3 is to help controling how long each video file will be saved
startTime3 = startTime1
# startTime4 is to help controling how long each audio file will be saved
startTime4 = startTime1
# create video file object...... maybe not necessary for project purpose
#out1 = cv.VideoWriter("D:/pyvidrec/rec_%03d.mp4", fourcc, fps, frameSize)
# determine how long should we run this program in seconds, 86400 s = 1 day
runningDur = 12
# determine time length of each saved video file in seconds
videoSaveIntv = 5
# determine interval of frame save in seconds
frameSaveIntv = 4
# determine time interval of audio recording start time in seconds
audioSaveIntv = 5

def saveAudioFile():
    sd.wait()
    audioWrite(audiofilename, fs, audiorecording)  # Save as WAV file 

# start the main loop
try:
    while cap.isOpened():
        # get a frame from camera, ret will return True if a frame is received
        ret, frame = cap.read()
        # get current time
        checkTime = datetime.now()
        
        # if no frame received, stop this program
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break

        # if the video save interval has passed, make flag1 = True
        if (checkTime - startTime3).total_seconds() >= videoSaveIntv:
            flag1 = True
        # if flag1 is True, create new video file
        if flag1 == True:
            out1 = cv.VideoWriter("D:/pyvidrec/%02d%02d%02d_%02d%02d.mp4" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute), fourcc, fps, frameSize)
            # reset startTime3 as checkTime
            startTime3 = checkTime
            flag1 = False
        # write the frame into the video file
        out1.write(frame)

        # if the frame save interval has passed since last time check, make the flag2 = True
        if (checkTime - startTime1).total_seconds() >= frameSaveIntv:
            flag2 = True
        # if flag2 is True, save current frame in an image file
        if flag2 == True:
            cv.imwrite("D:/pyvidrec/%02d%02d%02d_%02d%02d%02d.jpg" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute, checkTime.second),frame)
            # reset startTime1 as checkTime
            startTime1 = checkTime
            # turn flag to False
            flag2 = False

        # if the audio save interval has passed since last time check, make the flag3 = True
        if (checkTime - startTime4).total_seconds() >= audioSaveIntv:
            flag3 = True
            try:
                sd.stop()
                audioWrite(audiofilename, fs, audiorecording)
            except:
                traceback.print_exc()
            
        # if flag3 is True, start getting audio recording
        if flag3 == True:
            audiorecording = sd.rec(int(audirorecdur * fs))
            audiofilename = "D:/pyvidrec/%02d%02d%02d_%02d%02d%02d.wav" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute, checkTime.second)
            #saveAudioFileThread = Thread(target = saveAudioFile)
            #saveAudioFileThread.run()
            # reset startTime4 as checkTime
            startTime4 = checkTime
            # turn flag to False
            flag3 = False
        # if cv.waitKey(1) == ord('q'):
        #     break
    
        # if program has run for certain time, stop it
        if (checkTime - startTime2).total_seconds() >= runningDur:
            break

    # Release everything if job is finished
    cap.release()
    out1.release()

except KeyboardInterrupt:
    print("KeyboardInterrupt Exception is caught. Exiting program...")
    cap.release()
    out1.release()

except:
    traceback.print_exc()
    cap.release()
    out1.release()

该脚本给出了 output 个 2 个 mp4 文件、3 个 jpg 文件和 2 个 wav 文件。 只有 mp4 文件无法打开。 请帮我。

导致无法播放视频文件的问题很少:

  • 表达式frameSize = (cv.CAP_PROP_FRAME_WIDTH, cv.CAP_PROP_FRAME_HEIGHT)结果frameSize = (3, 4)
    正确的语法是从cap获取大小:

     frame_width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)) frameSize = (frame_width, frame_height)
  • 我们必须在打开一个新的 MP4 视频文件之前执行out1.release()
    在执行out1 = cv.VideoWriter之前,执行out1.release() ,除了第一次。
    我们可以在循环上方将out1初始化为None ,如果out1不是None则执行out1.release()

     if out1 is not None: out1.release() # Close the video file, before opening a new one out1 = cv.VideoWriter("D:/pyvidrec...

没有音频的代码示例:

import numpy as np
import cv2 as cv
from datetime import time, datetime, timedelta
#import sounddevice as sd
#from scipy.io.wavfile import write as audioWrite
#from threading import Thread
import traceback


cap = cv.VideoCapture(0) # use this line for testing with local camera (webcam, etc.)

# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'mp4v')
fps = 20.0
#frameSize = (640, 480)
#frameSize = (cv.CAP_PROP_FRAME_WIDTH, cv.CAP_PROP_FRAME_HEIGHT)
frame_width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
frameSize = (frame_width, frame_height)

# Define parameters for audio recording
#audirorecdur = 4
#fs= 44100
#sd.default.samplerate = fs
#sd.default.channels = 1
# flag to trigger video recording
flag1 = True
# flag to trigger frame capture
flag2 = True 
# flag to trigger audio recording
flag3 = True
# startTime1 is to help controlling when we will save a frame as an image file
startTime1 = datetime.now()
# startTime2 is to help controlling how long this script will run
startTime2 = startTime1
# startTime3 is to help controling how long each video file will be saved
startTime3 = startTime1
# startTime4 is to help controling how long each audio file will be saved
startTime4 = startTime1
# create video file object...... maybe not necessary for project purpose
#out1 = cv.VideoWriter("D:/pyvidrec/rec_%03d.mp4", fourcc, fps, frameSize)
# determine how long should we run this program in seconds, 86400 s = 1 day
runningDur = 12
# determine time length of each saved video file in seconds
videoSaveIntv = 5
# determine interval of frame save in seconds
frameSaveIntv = 4
# determine time interval of audio recording start time in seconds
audioSaveIntv = 5

#def saveAudioFile():
#    sd.wait()
#    audioWrite(audiofilename, fs, audiorecording)  # Save as WAV file 

out1 = None

# start the main loop
try:
    while cap.isOpened():
        # get a frame from camera, ret will return True if a frame is received
        ret, frame = cap.read()
        # get current time
        checkTime = datetime.now()
        
        # if no frame received, stop this program
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break

        # if the video save interval has passed, make flag1 = True
        if (checkTime - startTime3).total_seconds() >= videoSaveIntv:
            flag1 = True
        # if flag1 is True, create new video file
        if flag1 == True:
            if out1 is not None:
                out1.release()  # Close the video file, before opening a new one
            out1 = cv.VideoWriter("D:/pyvidrec/%02d%02d%02d_%02d%02d.mp4" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute), fourcc, fps, frameSize)
            # reset startTime3 as checkTime
            startTime3 = checkTime
            flag1 = False

        # write the frame into the video file
        if out1 is not None:
            out1.write(frame)

        # if the frame save interval has passed since last time check, make the flag2 = True
        if (checkTime - startTime1).total_seconds() >= frameSaveIntv:
            flag2 = True
        # if flag2 is True, save current frame in an image file
        if flag2 == True:
            cv.imwrite("D:/pyvidrec/%02d%02d%02d_%02d%02d%02d.jpg" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute, checkTime.second),frame)
            # reset startTime1 as checkTime
            startTime1 = checkTime
            # turn flag to False
            flag2 = False

        # if the audio save interval has passed since last time check, make the flag3 = True
        #if (checkTime - startTime4).total_seconds() >= audioSaveIntv:
        #    flag3 = True
        #    try:
        #        sd.stop()
        #        audioWrite(audiofilename, fs, audiorecording)
        #    except:
        #        traceback.print_exc()
            
        # if flag3 is True, start getting audio recording
        #if flag3 == True:
        #    audiorecording = sd.rec(int(audirorecdur * fs))
        #    audiofilename = "D:/pyvidrec/%02d%02d%02d_%02d%02d%02d.wav" % (checkTime.year-2000, checkTime.month, checkTime.day, checkTime.hour, checkTime.minute, checkTime.second)
        #    #saveAudioFileThread = Thread(target = saveAudioFile)
        #    #saveAudioFileThread.run()
        #    # reset startTime4 as checkTime
        #    startTime4 = checkTime
        #    # turn flag to False
        #    flag3 = False
        ## if cv.waitKey(1) == ord('q'):
        #     break
    
        # if program has run for certain time, stop it
        if (checkTime - startTime2).total_seconds() >= runningDur:
            break

    # Release everything if job is finished
    cap.release()
    out1.release()

except KeyboardInterrupt:
    print("KeyboardInterrupt Exception is caught. Exiting program...")
    cap.release()
    out1.release()

except:
    traceback.print_exc()
    cap.release()
    out1.release()

笔记:
下次您发布问题时,请发布一个最小的可重现代码示例 - 创建一个干净的代码示例,排除所有与问题无关的部分(例如:音频与视频问题无关)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM