Skip to content

Commit

Permalink
Modified scripts, configs for video image
Browse files Browse the repository at this point in the history
Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
  • Loading branch information
VietND96 committed Oct 16, 2023
1 parent 6aed36b commit acf8e47
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 29 deletions.
14 changes: 7 additions & 7 deletions Video/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ minprocs=200 ; (min. avail process descriptors;

[program:video-recording]
priority=0
command=/opt/bin/video.sh
command=bash -c "/opt/bin/video.sh; EXIT_CODE=$?; kill -s SIGTERM `cat /var/run/supervisor/supervisord.pid`; exit $EXIT_CODE"
autostart=true
autorestart=true
stopsignal=INT
autorestart=unexpected
stopsignal=TERM

;Logs (all activity redirected to stdout so it can be seen through "docker logs"
redirect_stderr=true
Expand All @@ -25,12 +25,12 @@ stdout_logfile_maxbytes=0

[program:video-ready]
priority=5
command=python3 /opt/bin/video_ready.py
command=bash -c "python3 -u /opt/bin/video_ready.py; EXIT_CODE=$?; kill -s SIGTERM `cat /var/run/supervisor/supervisord.pid`; exit $EXIT_CODE"
autostart=true
autorestart=true
stopsignal=INT
autorestart=unexpected
stopsignal=TERM

;Logs (all activity redirected to stdout so it can be seen through "docker logs"
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stdout_logfile_maxbytes=0
105 changes: 86 additions & 19 deletions Video/video.sh
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash

VIDEO_SIZE="${SE_SCREEN_WIDTH}""x""${SE_SCREEN_HEIGHT}"
DISPLAY_CONTAINER_NAME=${DISPLAY_CONTAINER_NAME}
Expand All @@ -7,22 +7,89 @@ FILE_NAME=${FILE_NAME}
FRAME_RATE=${FRAME_RATE:-$SE_FRAME_RATE}
CODEC=${CODEC:-$SE_CODEC}
PRESET=${PRESET:-$SE_PRESET}
VIDEO_FOLDER=${SE_VIDEO_FOLDER}

return_code=1
max_attempts=50
attempts=0
echo 'Checking if the display is open...'
until [ $return_code -eq 0 -o $attempts -eq $max_attempts ]; do
xset -display ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM} b off > /dev/null 2>&1
return_code=$?
if [ $return_code -ne 0 ]; then
echo 'Waiting before next display check...'
sleep 0.5
fi
attempts=$((attempts+1))
done

# exec replaces the video.sh process with ffmpeg, this makes easier to pass the process termination signal
exec ffmpeg -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0 -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p "$VIDEO_FOLDER/$FILE_NAME"

function get_session_id {
session_id=$(curl -s --request GET 'http://'${DISPLAY_CONTAINER_NAME}':'${SE_NODE_PORT}'/status' | jq -r '.[]?.node?.slots | .[0]?.session?.sessionId')
}

function star_recording {
video_file_name="${SE_VIDEO_FOLDER}/$session_id.mp4"
ffmpeg -nostdin -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0 -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p $video_file_name &
FFMPEG_PID=$!
recording_started="true"
}

function stop_recording {
kill -s SIGINT ${FFMPEG_PID}
wait ${FFMPEG_PID}
recording_started="false"
recorded_count=$((recorded_count+1))
}

function terminate_gracefully {
echo "Trapped SIGTERM/SIGINT/x so shutting down video-recording..."
while true;
do
get_session_id
if [ "$session_id" != "null" -a "$session_id" != "" ] && [ $recording_started = "true" ];
then
echo "Session: $session_id is active, waiting for it to finish"
sleep 1
else
pkill --signal TERM -f "ffmpeg"
break
fi
done
pkill --signal TERM -f "video_ready.py"
echo "Shutdown completed!"
}

if [ "${SE_VIDEO_RECORD}" = "true" ];
then
max_recorded_count=$((${DRAIN_AFTER_SESSION_COUNT:-SE_DRAIN_AFTER_SESSION_COUNT}))
recorded_count=0
return_code=1
max_attempts=50
attempts=0
recording_started="false"
video_file_name=""

trap terminate_gracefully SIGTERM SIGINT

echo 'Checking if the display is open...'
until [ $return_code -eq 0 -o $attempts -eq $max_attempts ]; do
xset -display ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM} b off > /dev/null 2>&1
return_code=$?
if [ $return_code -ne 0 ]; then
echo 'Waiting before next display check...'
sleep 0.5
fi
attempts=$((attempts+1))
done

while true;
do
get_session_id
if [ "$session_id" != "null" -a "$session_id" != "" ] && [ $recording_started = "false" ];
then
echo "Reached session: $session_id"
echo "Starting to record video"
star_recording
echo "Video recording started"
elif [ "$session_id" = "null" -o "$session_id" = "" ] && [ $recording_started = "true" ];
then
echo "Stopping to record video"
stop_recording
echo "Video recording stopped"
if [ $max_recorded_count -gt 0 ] && [ $recorded_count -ge $max_recorded_count ];
then
echo "Max recorded count reached, exiting"
exit 0
fi
elif [ $recording_started = "true" ];
then
echo "Video recording in progress"
fi
sleep 1
done
fi
66 changes: 63 additions & 3 deletions Video/video_ready.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,78 @@
from os import environ
import json
import psutil
import time
import signal
import sys

video_ready_port = int(environ.get('VIDEO_READY_PORT', 9000))

class Handler(BaseHTTPRequestHandler):

def do_GET(self):
video_ready = "ffmpeg" in (p.name().lower() for p in psutil.process_iter())
response_code = 200 if video_ready else 404
response_text = "ready" if video_ready else "not ready"
if self.path == '/recording':
self.video_recording()
elif self.path == '/status':
self.video_status()
else:
self.video_status()

def do_POST(self):
if self.path == '/drain':
self.video_drain()

def video_recording(self):
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps(Handler.is_recording()).encode('utf-8'))

def video_status(self):
video_status = Handler.is_alive()
response_code = 200 if video_status else 404
self.send_response(response_code)
self.end_headers()
self.wfile.write(json.dumps(video_status).encode('utf-8'))

def video_drain(self):
recording = Handler.is_recording()
response_text = 'waiting for recording to be completed' if recording else 'terminating now'
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps({'status': response_text}).encode('utf-8'))
quit()

@staticmethod
def terminate_gracefully(signum, stack_frame):
print("Trapped SIGTERM/SIGINT/x so shutting down video-ready...")
while Handler.is_recording():
time.sleep(1)
quit()

@staticmethod
def is_alive():
return Handler.is_proc_running("video.sh")

@staticmethod
def is_recording():
return Handler.is_proc_running("ffmpeg")

@staticmethod
def is_proc_running(process_name):
for proc in psutil.process_iter():
if process_name in "".join(proc.cmdline()):
return True
return False

@staticmethod
def stop_proc(process_name):
for proc in psutil.process_iter():
if process_name in "".join(proc.cmdline()):
proc.terminate()
print("Terminated process: " + process_name)

# register SIGTERM handlers to enable graceful shutdown of recording
signal.signal(signal.SIGINT, Handler.terminate_gracefully)
signal.signal(signal.SIGTERM, Handler.terminate_gracefully)

httpd = HTTPServer( ('0.0.0.0', video_ready_port), Handler )
httpd.serve_forever()

0 comments on commit acf8e47

Please sign in to comment.