Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions camera_stream_recording/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM python:3.7

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "python","-u", "./async_wrapper.py" ]
19 changes: 19 additions & 0 deletions camera_stream_recording/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## deploy 24/7 recording to aks
To have a 24/7 recording running in kubernetes and storing the results to azure blob follow these steps
````bash
az login
az acr login --name fkkstudents
````
make sure you are in the ./camera_stream_recording/src folder
````bash
docker build -t fkkstudents.azurecr.io/recording/camera_recorder .
docker push fkkstudents.azurecr.io/recording/camera_recorder
````

get .env file with the correct credentials (a backup is stored in the SaveNow storage account fkk247/credentials)

````bash
az aks get-credentials --resource-group fkkstudents --name fkkstudents
kubectl apply -f deployament.yaml
````

## Capture Videostream

This tool has two basic mode. At first you can generate training data for manual labeling in cvat [here is the relevant fork](https://github.com/jul095/cvat).
Expand Down
45 changes: 23 additions & 22 deletions camera_stream_recording/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,26 @@ def is_video_consistent(filename, video_duration):
:return: if the video is consistent due to a threshold
:rtype: bool
"""
video_length = get_length(filename)
# Check if video is 8 percent shorter than expected
# check if the video is shorter than the expected length. This could be a "jump" in the video -> delete video
expected_length = video_duration
tolerance = expected_length - (expected_length * 0.1)
if video_length < tolerance:
print('video is 1 percent shorter than expected:')
print('video_length: ' + str(video_length))
print('expected_length: ' + str(expected_length))
print('tolerance: ' + str(tolerance))
return False
else:
print('video_length: ' + str(video_length))
print('expected_length: ' + str(expected_length))
# This is causing weird "file not found" issues --> uncommenting for now. MJ 21.03.2021

# video_length = get_length(filename)
# # Check if video is 8 percent shorter than expected
# # check if the video is shorter than the expected length. This could be a "jump" in the video -> delete video
# expected_length = video_duration
# tolerance = expected_length - (expected_length * 0.1)
# if video_length < tolerance:
# print('video is 1 percent shorter than expected:')
# print('video_length: ' + str(video_length))
# print('expected_length: ' + str(expected_length))
# print('tolerance: ' + str(tolerance))
# return False
# else:
# print('video_length: ' + str(video_length))
# print('expected_length: ' + str(expected_length))
return True


def upload_video(filename, uploads_list, storage_addr, sas_token):
def upload_video(filename, SAS_TOKEN, STORAGE_ACCOUNT, STORAGE_CONTAINER):
"""
Prepare the upload of files to a azure Filestorage

Expand All @@ -89,16 +91,15 @@ def upload_video(filename, uploads_list, storage_addr, sas_token):
:return: -
:rtype: void
"""
print("Upload file " + filename)
dest = storage_addr + filename + sas_token

sub_p_id = subprocess.Popen(["./azcopy", "copy", filename, dest],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
uploads_list.append([sub_p_id, filename])
print("Uploading file %s to %s / %s " % (filename, STORAGE_ACCOUNT, STORAGE_CONTAINER))
block_blob_service = BlockBlobService(account_name=STORAGE_ACCOUNT, sas_token=SAS_TOKEN)
block_blob_service.create_blob_from_path(STORAGE_CONTAINER, filename, filename)
print("Upload successfull. Removing local file %s" % filename)
os.remove(filename)
return



def get_end_timestamp_from_minutes_duration(video_max_duration):
return datetime.now() + timedelta(minutes=video_max_duration)

Expand Down
6 changes: 6 additions & 0 deletions camera_stream_recording/async_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import time
from subprocess import Popen
while True:
print("starting new process with video_recording_main.py")
p = Popen('python main.py -u -p -vd 10', shell=True)
time.sleep(600)
27 changes: 27 additions & 0 deletions camera_stream_recording/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
kind: Namespace
apiVersion: v1
metadata:
name: camera-recorder
labels:
name: camera-recorder
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: camera-recorder-deployment
namespace: camera-recorder
labels:
app: camera-recorder
spec:
replicas: 1
selector:
matchLabels:
app: camera-recorder
template:
metadata:
labels:
app: camera-recorder
spec:
containers:
- name: camera-recorder
image: fkkstudents.azurecr.io/recording/camera_recorder:latest
3 changes: 2 additions & 1 deletion camera_stream_recording/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ CAMERA_IP_ADDR=
CAMERA_USER_NAME=
PASSWORD=
SAS_TOKEN=
STORAGE_ADDR=
STORAGE_ACCOUNT=
STORAGE_CONTAINER=
23 changes: 14 additions & 9 deletions camera_stream_recording/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,24 @@ def __init__(self, username, password, ip_addr, is_uploaded):
self.fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
self.link = f"rtsp://{username}:{password}@{ip_addr}:80/axis-media/media.amp?streamprofile=rtspStreamLow"
self.cap = cv2.VideoCapture(self.link)
print(self.link)
self.uploads = []
self.is_uploaded = is_uploaded
if not self.cap.isOpened():
raise RuntimeError("Connection to camera is not working")

def start_capture_one_video(self):
"""Initialize the Video Writer"""
vid_name = generate_unique_name() + ".mp4"
out = cv2.VideoWriter(vid_name, self.fourcc, 30.0,
(1920, 1080))
vid_name = generate_unique_name() + ".avi"
fourcc = cv2.VideoWriter_fourcc(*'MPEG')
out = cv2.VideoWriter(vid_name, fourcc, 30.0,
(1920, 1080))
return vid_name, out

def handle_video_saving(self, filename, sub_procs_list, video_duration):
"""Method will start uploading videos and delete the files if there are not consistent"""
if is_video_consistent(filename, video_duration):
if self.is_uploaded:
upload_video(filename, sub_procs_list, config('STORAGE_ADDR'), config('SAS_TOKEN'))
upload_video(filename, config('SAS_TOKEN'), config('STORAGE_ACCOUNT'),config('STORAGE_CONTAINER') )
else:
print("No upload, because the script runs locally\n")
else:
Expand All @@ -66,7 +66,7 @@ def handle_video_saving_specific_time(self, filename, sub_procs_list,
"""Method will start uploading and keep the files if there are not consistent"""
if is_video_consistent(filename, video_duration):
if self.is_uploaded:
upload_video(filename, sub_procs_list, config('STORAGE_ADDR'), config('SAS_TOKEN'))
upload_video(filename, config('SAS_TOKEN'), config('STORAGE_ACCOUNT'),config('STORAGE_CONTAINER') )
else:
print("No upload, because the script runs locally\n")
else:
Expand Down Expand Up @@ -130,7 +130,7 @@ def capture_video_stream_for_specific_time(self, end_timestamp=None):

cam_connect = self.cap.read()
time.sleep(0.5)
cv2.namedWindow("CameraView", cv2.WINDOW_NORMAL)
# cv2.namedWindow("CameraView", cv2.WINDOW_NORMAL)
while True:
prev_stream_frame = stream_frame
try:
Expand Down Expand Up @@ -164,7 +164,7 @@ def capture_video_stream_for_specific_time(self, end_timestamp=None):
vis_frame = Display("Connect: " + str(connect_count), vis_frame,
(5, 80)).overlay_text()
if cam_connect:
cv2.imshow("CameraView", vis_frame)
# cv2.imshow("CameraView", vis_frame)
self.out.write(stream_frame)

if end_timestamp is not None:
Expand All @@ -187,7 +187,7 @@ def capture_video_stream_for_specific_time(self, end_timestamp=None):
self.handle_video_saving_specific_time(self.vid_name, self.uploads,
expected_length)
self.check_for_completed_uploads(self.uploads, None)
cv2.destroyAllWindows()
# cv2.destroyAllWindows()
# self.match_with_first_timestamp()

def match_with_first_timestamp(self):
Expand Down Expand Up @@ -299,6 +299,10 @@ def capture_images_every_minute(self, runtime_duration):
if datetime.datetime.now() >= end_time_script:
break

def entry_for_async_recording():
video_capturing = MainCaptureHandling(config('CAMERA_USER_NAME'),
config('PASSWORD'), config('CAMERA_IP_ADDR'), True)
video_capturing.capture_video_stream_for_specific_time(get_end_timestamp_from_minutes_duration(1))

if __name__ == "__main__":

Expand Down Expand Up @@ -352,6 +356,7 @@ def capture_images_every_minute(self, runtime_duration):
# Run only one planned capturing of one video user defined
if args.video_duration:
vdm_duration = args.video_duration
print("running planned video capturing for a specific time")
video_capturing.capture_video_stream_for_specific_time(
get_end_timestamp_from_minutes_duration(vdm_duration))
else:
Expand Down
1 change: 1 addition & 0 deletions camera_stream_recording/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ opencv-python==4.3.0.36
python-dateutil==2.8.1
python-decouple==3.4
six==1.15.0
azure-storage-blob==2.1.0