Hello everyone! So great to use Streamlit for my projects, thank you so much for your work and dedication!
My question is something similar to this topic. I also want to upload video to my Streamlit app. And I also want to process each frame with OpenCV functions (and also with some Neural Network model).
What I want to do next is to display a processed video on my web page generated with Streamlit app. In the topic that I attached to this question before, the author just displays processed frames one by one with st.empty() method. But this will not work for me. As I mentioned I am going to use some heavy functions and NN models to process my video. So processing of the full 5 sec video row might take around 50 sec. If I display each frame of a video after itâs full processing, the frame rate will be just too low. So instead I want first to fully process the video and only then I want to display it on my web app, ideally with st.video() method. The best way to do that in my opinion is to write a ready video on a drive using OpenCV method cv2.VideoWriter and then open it as BytesIO object and display it with st.video() method.
So as I see a full pipeline, I want to upload a video to my app, save it as a temporary file on a drive at my backend side, read it with OpenCV (cv2.VideoCapture), process frame by frame and save it frame by frame with cv2.VideoWriter method to another temporary file and then open it and run with st.video() method.
My problem is that I canât write a video to a drive with cv2.VideoWriter. This method works well when I run it from console or IDE, but it doesnât work when I run my Streamlit app (it creates temp file on my drive, but its size is zero). I just donât understand what is wrong here. Hereâs the code:
import streamlit as st
import cv2
video_data = st.file_uploader("Upload file", ['mp4','mov', 'avi'])
# func to save BytesIO on a drive
def write_bytesio_to_file(filename, bytesio):
"""
Write the contents of the given BytesIO to a file.
Creates the file or overwrites the file if it does
not exist yet.
"""
with open(filename, "wb") as outfile:
# Copy the BytesIO stream to the output file
outfile.write(bytesio.getbuffer())
if video_data:
# save uploaded video to disc
temp_file_to_save = 'c:/temp_file_1.mp4'
write_bytesio_to_file(temp_file_to_save, video_data)
# read it with cv2.VideoCapture(), so now we can process it with OpenCV functions
cap = cv2.VideoCapture(temp_file_to_save)
# grab some parameters of video to use them for writing a new, processed video
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_fps = int(cap.get(cv2.CAP_PROP_FPS))
st.write(width, height, frame_fps)
# specify a writer to write a processed video to a disk frame by frame
temp_file_result = 'c:/temp_file_2.mp4'
fourcc_mp4 = cv2.VideoWriter_fourcc(*'XVID')
out_mp4 = cv2.VideoWriter(temp_file_result, fourcc_mp4, frame_fps, (width, height))
# loop though a video, process each frame and save it to a disk
while True:
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
st.write("Can't receive frame (stream end?). Exiting ...")
break
# some video processing here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# write a processed frame to the video on a disk
out_mp4.write(gray)
# when video is fully saved to disk, open it as BytesIO and play with st.video()
result_video = open(temp_file_result, "rb")
st.video(result_video)
Any ideas why it doesnât work? Maybe some conflict between a loop of Streamlit (as it reads through the whole code again and again) and a loop that processes and saves a video? Maybe there is some other way to implement my plan? I will be glad to get any help. I am also open for any ideas. Thank you!