Reputation: 341
I'm trying to use Boto3 to get a video stream from kinesis and then use OpenCV to display the feed and save it to a file at the same time.
The process of getting the signed URL and then the Getmedia request seems to work perfectly it's just when I'm trying to render it using OpenCV it doesn't seem to work.
Data is defiantly going to the stream
import boto3
import numpy as np
import cv2
kinesis_client = boto3.client('kinesisvideo',
region_name='eu-west-1',
aws_access_key_id='ACC',
aws_secret_access_key='KEY'
)
response = kinesis_client.get_data_endpoint(
StreamARN='ARN',
APIName='GET_MEDIA'
)
video_client = boto3.client('kinesis-video-media',
endpoint_url=response['DataEndpoint']
)
stream = video_client.get_media(
StreamARN='ARN',
StartSelector={'StartSelectorType': 'NOW'}
)
# print(stream)
datafeed = stream['Payload'].read()
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while(True):
ret, frame = stream['Payload'].read()
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
Upvotes: 12
Views: 5898
Reputation: 11583
You could do something like this. It's very simple, but not perfect (parsing the mkv in the stream could be better, so the beginning/end is always correct). Also, it won't work if the mkv's in the stream are smaller than 1024 bytes.
import boto3
import cv2
kinesis_client = boto3.client("kinesisvideo", region_name="eu-central-1")
get_media_response = kinesis_client.get_data_endpoint(StreamName="my_stream_name", APIName="GET_MEDIA")
video_client = boto3.client("kinesis-video-media", endpoint_url=get_media_response["DataEndpoint"], region_name="eu-central-1")
stream = video_client.get_media(StreamName="my_stream_name", StartSelector={"StartSelectorType": "NOW"})
mkv = b''
while True:
chunk = stream["Payload"].read(1024)
if chunk == b'':
# nothing in the stream
# you could wait a little and try again
break
if mkv == b'':
mkv += chunk
else:
index = chunk.find(b'\x1aE\xdf\xa3') # magic numbers marking the beginning of an mkv
if index == -1:
mkv += chunk
else:
mkv += chunk[0:index]
# process mkv
with open("file.mkv", "wb") as f:
f.write(mkv)
video = cv2.VideoCapture("file.mkv")
while video.isOpened():
ret, frame = video.read()
if ret:
cv2.imshow("Frame", frame)
else:
break
mkv = chunk[index:]
Upvotes: 0
Reputation: 341
To finally answer this I found a basic solution using the HLS Output available form kineses video streams. Which became available JUL 2018
Ive pasted the working version of my code below.
Im using AWS ENV varables for the BOTO3 authtication.
import boto3
import cv2
STREAM_NAME = "test-stream"
kvs = boto3.client("kinesisvideo")
# Grab the endpoint from GetDataEndpoint
endpoint = kvs.get_data_endpoint(
APIName="GET_HLS_STREAMING_SESSION_URL",
StreamName=STREAM_NAME
)['DataEndpoint']
print(endpoint)
# # Grab the HLS Stream URL from the endpoint
kvam = boto3.client("kinesis-video-archived-media", endpoint_url=endpoint)
url = kvam.get_hls_streaming_session_url(
StreamName=STREAM_NAME,
PlaybackMode="LIVE"
)['HLSStreamingSessionURL']
vcap = cv2.VideoCapture(url)
while True:
# Capture frame-by-frame
ret, frame = vcap.read()
if frame is not None:
# Display the resulting frame
cv2.imshow('frame',frame)
# Press q to close the video windows before it ends if you want
if cv2.waitKey(22) & 0xFF == ord('q'):
break
else:
print("Frame is None")
break
# When everything done, release the capture
vcap.release()
cv2.destroyAllWindows()
print("Video stop")
Upvotes: 10