I have code working for streaming video. I got nice code from other users in the forum. The use-case I am struggling with is how to upload a local file.
In a method I have the following:
@st.cache(allow_output_mutation=True)
def get_cap(uploaded_file):
return cv2.VideoCapture(uploaded_file)
uploaded_file = st.file_uploader("Choose a video...", type=["mp4", "mpeg"])
if uploaded_file is not None:
return uploaded_file
This returns an object of type _io.BytesIO
From this I want to pass it to openCV in the usual manner.
while True:
image = get_cap(uploaded_file).read()
try:
image = cv2.resize(image, None, fx=scaling_factorx, fy=scaling_factory, interpolation=cv2.INTER_AREA)
# do other video stuff
except:
break
This is the error I get:
UnhashableType: Cannot hash object of type _io.BytesIO
While caching some code, Streamlit encountered an object of type _io.BytesIO. You’ll need to help Streamlit understand how to hash that type with the hash_funcs argument. For example:
@st.cache(hash_funcs={_io.BytesIO: my_hash_func})
def my_func(...):
...
Please see the hash_funcs documentation for more details.
How can I upload and run processes on a local video file in streamlit?
What Streamlit version are you running? If not currently on 0.59.0, any chance you could update and see if you’re still having the issue? BytesIO is now natively supported.
This almost works but it seems there may be something going on with the caching and playing the video while it is being written. I can write it to disk but then the .read() method breaks for some reason. I will try and figure this out. May need to pause any processing until the video is uploaded?
The video should be uploaded when you have the bytesio, are you closing the file? I’d suggest writing to disk and returning a filename all inside a cached function.
Here is a complete proof of concept. I expect that I can upload a video and it should play. I should be able to upload the same video if I want.
What is happening now is it will play the first time I upload it. If I try to upload another file the resize errors out. It returns an image of size 0. Sorry the code is a bit sloppy, thanks!
import streamlit as st
import io
import cv2
st.title("Play Uploaded File")
uploaded_file = st.file_uploader("Choose a video...", type=["mp4"])
temporary_location = False
if uploaded_file is not None:
g = io.BytesIO(uploaded_file.read()) ## BytesIO Object
temporary_location = "testout_simple.mp4"
with open(temporary_location, 'wb') as out: ## Open temporary file as bytes
out.write(g.read()) ## Read bytes into file
# close file
out.close()
@st.cache(allow_output_mutation=True)
def get_cap(location):
print("Loading in function", str(location))
video_stream = cv2.VideoCapture(str(location))
# Check if camera opened successfully
if (video_stream.isOpened() == False):
print("Error opening video file")
return video_stream
scaling_factorx = 0.25
scaling_factory = 0.25
image_placeholder = st.empty()
if temporary_location:
while True:
# here it is a CV2 object
video_stream = get_cap(temporary_location)
# video_stream = video_stream.read()
ret, image = video_stream.read()
if ret:
image = cv2.resize(image, None, fx=scaling_factorx, fy=scaling_factory, interpolation=cv2.INTER_AREA)
else:
print("there was a problem or video was finished")
cv2.destroyAllWindows()
video_stream.release()
break
# check if frame is None
if image is None:
print("there was a problem None")
# if True break the infinite loop
break
image_placeholder.image(image, channels="BGR", use_column_width=True)
cv2.destroyAllWindows()
video_stream.release()
cv2.destroyAllWindows()