1

I am trying to record the Logitech Webcam video. The cam is able to record it but 40 sec video is recorded for only 6 seconds with some nX speed. I referred the following link for the solution but it couldn't solves the problem in RPi. The important thing is the code works find in Ubuntu desktop but may be RPi is slower to process.

Here is my code snippet:

fourcc = cv2.cv.CV_FOURCC(*'XVID')
videoOut = cv2.VideoWriter("video_clip.avi", fourcc, 20.0, (640, 480))
start_time = time.time()
frame_count = 0
while True:
    ret, frame = cap.read()
    videoOut.write(frame)  # write each frame to make video clip
    frame_count += 1

    print int(time.time()-start_time)  # print the seconds
    if int(time.time()-start_time) == 10:
        videoOut.release()
        break
        # get out of loop after 10 sec video
print 'frame count =', frame_count 
# gives me 84 but expected is 20.0 * 10 = 200
Prasad
  • 611
  • 1
  • 5
  • 17
  • Are you using the same camera on both Desktop and RPI? – zindarod Jun 29 '18 at 08:51
  • I don't understand: Does it record 40 seconds long but playback is too fast so 40 seconds are shrunk to 6 seconds? Or does it stop recording after 6 seconds? What's the frame rate of your camera? Can you measure the captured frame rate for x seconds with and without encoding/writing to spot bottlenecks? – Micka Jun 29 '18 at 08:53
  • probably the rpi can't encode xvid fast enough. – Micka Jun 29 '18 at 08:55
  • @zindarod yes both camera are same which logitech c270 – Prasad Jun 29 '18 at 09:03
  • @Micka playback is too fast so 40 seconds are shrunk to 6 seconds, frame rate is 20 fps – Prasad Jun 29 '18 at 09:03
  • so either your camera does not deliver the 20 fps (but then your desktop pc would show the same behaviour) or your capturing and recording is too slow (so frames are dropped), which can easily be the case on a raspberry pi. You could try to buffer the frames, to use a cheaper encoder and some other optimizations to test and maybe overcome that problem. If you don't care about getting 20 fps but just want the RIGHT fps playback, you can first measure the captured fps during some short test duration and then create a new VideoWriter with the right fps value. – Micka Jun 29 '18 at 09:27
  • Thanks for your support Micka. I got it – Prasad Jun 29 '18 at 09:30

2 Answers2

4

I had the same question some time ago. I did a lot of searching, but did not find a solution. The problem is the fps passed is the rate at which the video will be played. It does not mean that the video will be recorded at that FPS. AFAIK, there is no direct way to set the recorded FPS. If your recorded FPS had been too high, you could downsample (ie keep only 1 frame for each time period). But from what you describe, it seems that it is much lower than required. This is a hardware limitation and nothing can be done about it.

With respect to setting the recorded FPS, I found a workaround. I create the videoWriter after capturing all the frames in a list. In this way, I can calculate the recorded FPS and pass it to VideoWriter when creating it.

Meet Taraviya
  • 789
  • 1
  • 7
  • 24
2

Making a list of frames might not work if you run out of memory. The alternative can be to calculate the fps dynamically and then remux the video with the new fps using ffmpeg.

import numpy as np
from skvideo import io
import cv2, sys
import time
import os

if __name__ == '__main__':

    file_name = 'video_clip.avi'

    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    videoOut = cv2.VideoWriter(file_name, fourcc, 30.0, (640, 480))
    cap = cv2.VideoCapture(0)

    if not cap.isOpened() or not videoOut.isOpened():
        exit(-1)

    start_time = time.time()
    frame_count = 0
    duration = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            print('empty frame')
            break
        videoOut.write(frame)  # write each frame to make video clip
        frame_count += 1

        duration = time.time()-start_time
        if int(duration) == 10:
            videoOut.release()
            cap.release()
            break

    actualFps = np.ceil(frame_count/duration)

    os.system('ffmpeg -y -i {} -c copy -f h264 tmp.h264'.format(file_name))
    os.system('ffmpeg -y -r {} -i tmp.h264 -c copy {}'.format(actualFps,file_name))
zindarod
  • 5,532
  • 2
  • 23
  • 50