Ali Khan AK
Ali Khan AK

Reputation: 87

Video Writing using opencv but output file is not playable

I want to write a video file using two videos side-by-side, but at the end the output file is not playable in any video player. This is my code:

from __future__ import print_function
import numpy as np
import argparse
import cv2
import tkinter as tk
from tkinter import filedialog
import os
import os.path

ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", type=str, default="sample.avi",
            help="path to output video file")
ap.add_argument("-f", "--fps", type=int, default=100.0,
            help="FPS of output video")
ap.add_argument("-c", "--codec", type=str, default="MJPG",
            help="codec of output video")
args = vars(ap.parse_args())

root = tk.Tk()
root.withdraw()

source_video = filedialog.askopenfilename(title="Select file")
sign = filedialog.askopenfilename(title="Select file")
print("[INFO] Capturing video...")
cap1 = cv2.VideoCapture(source_video)
cap2 = cv2.VideoCapture(sign)

fourcc = cv2.VideoWriter_fourcc(*args["codec"])
writer = None
(h, w) = (None, None)
zeros = None
i = 0 
try:
    while cap1.isOpened():
        ret, frame1 = cap1.read()
        if ret:
            frame1 = cv2.resize(frame1, (0, 0), fx=0.5, fy=0.5)
            (h, w) = frame1.shape[:2]

            ret, frame2 = cap2.read()
            if ret:
                frame2 = cv2.resize(frame2, (w, h))

        else:
            break

        if writer is None:
            writer = cv2.VideoWriter(args["output"], fourcc, args["fps"], 
(h, w*2), True)
            zeros = np.zeros((h, w*2), dtype="uint8")
        output = np.zeros((h, w*2, 3), dtype="uint8")

        if frame2 is None:
            output[0:h, 0:w] = frame1
            writer.write(output)
        else:
            output[0:h, 0:w] = frame1
            output[0:h, w:w * 2] = frame2
            writer.write(output)

        cv2.imshow('output', output)
        if cv2.waitKey(25) & 0xFF == ord('q'):
            break

    writer.release()
    cv2.destroyAllWindows()


except Exception as e:
        print(str(e))

I don't get any error all the things going well but when I try to play output video file from the directory it will not play. I also check file size which is about 16KB. I don't know where the problem exist. please help me. I'm using: Windows 10 64-bit Python3.7 Pycharm as IDE

Upvotes: 5

Views: 8727

Answers (2)

Guillermo Arias
Guillermo Arias

Reputation: 31

** Solved ** The problem happens when your camera generates a video size different than the video size of the file you are trying to create.

For example: my IP camera generates frames of size(1920,1080) and in the tutorial i found the code they are trying to write a file with the size (640,480).

What i did for solving the problem is to take the width and height from the video camera and put them into the videoWriter method.

Here you have the code that will work with any size of video:

import cv2

# desde la vídeo cámara: indicar ruta IP del stream
# desde file, indicar ruta de archivo
# desde cámara web: usar el número 0,1 ó -1
cap = cv2.VideoCapture('rtsp://admin:[email protected]:554/Streaming/Channels/1')


# fourcc es el código del tipo de vídeo XVID = MPEG4
fourcc = cv2.VideoWriter_fourcc(*'XVID')

print("vídeo operativo: ",cap.isOpened())

videoWidth = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
videoHeight = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

print("ancho: ",videoWidth)
print("altura: ",videoHeight)

#  20= frames x segundo, (640x480) = tamaño del vídeo que grabaremos
# el tamaño del vídeo que se grabará debe ser igual al capturado de la cámara
out = cv2.VideoWriter('output_file.avi',fourcc, 20.0,(videoWidth,videoHeight))


while(cap.isOpened()): # si el file no existe, o no hay vídeo de la fuente indicada, dará False
    # en este bucle se captura el vídeo frame por frame (cuadro por cuadro)
    ret,frame = cap.read() # "ret" puede ser t/f dependiendo si se captura vídeo o no, "frame" contendrá el vídeo
    if ret == True:
        out.write(frame)  # escribir en el file
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # convertir a gris el vídeo
        cv2.imshow('frame',gray)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()
out.release()
cv2.destroyAllWindows()

Upvotes: 3

Ulrich Stern
Ulrich Stern

Reputation: 11301

The frameSize parameter for VideoWriter is (width, height), which is somewhat hidden in the docs (e.g., here). So in your code, it should be

writer = cv2.VideoWriter(args["output"], fourcc, args["fps"], (w*2, h), True)

After this fix, your code produced working videos for me.

I noticed that your code "learns" the frame size from the input video but not the frame rate, but I assume this is intentional.

Upvotes: 10

Related Questions