diff --git a/.gitignore b/.gitignore index f72abb1..6ca86c1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,13 @@ CMakeCache.txt Makefile boardCropCoordinates.txt Track4K +*.pyc +__pycache__/ +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +.retry diff --git a/README.md b/README.md index c815904..1a92941 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,21 @@ Track4K is an open source C++ project that takes a High Definition video of a lecture recording and then produces a smaller cropped output video, which frames the lecturer. This is done using image processing and computer vision algorithms to track the lecturer and uses the lecturer position information to pan the virtual camera. ## Getting Started + +> If you want to use right away go to [this link](/utils/Ansible_Playbook) to install Track4K automatically. + These instructions will help get the program and all its dependencies set up on your machine. +> Please take note that this installation guide It was made for use under Ubuntu 16.04, some changes may apply for other distributions or Ubuntu variations. + +> All the commands are run as normal user unless if its written as super user "\#" + + + + + ### Prerequisites -These instructions are written with the assumption that the project will be installed on a Linux-based system (preferably a Debian version). Track4K has been tested on Ubuntu 16.04 +These instructions are written with the assumption that the project will be installed on a Linux-based system (preferably a Debian version). **Track4K has been tested on Ubuntu 16.04** To be able to run this project, you will need to first install the following dependencies: @@ -16,85 +27,117 @@ These instructions are written with the assumption that the project will be inst * CMake (3.8.0 or future releases) * git (2.10.2 or future releases) -### Installation -#### FFmpeg -The standard repositories of your distribution may include FFmpeg 3.4+. If not, FFmpeg 3.4 can be built from source (more on that topic [here](https://github.com/FFmpeg/FFmpeg/blob/master/INSTALL.md)). -For Ubuntu-based distributions, the PPA `ppa:jonathonf/ffmpeg-3` allows for simpler installation without the needing to build from source. The PPA can be added as follows: +## Installation of the requirements + + +First go to any folder to work with the files that will be downloaded and installed. Next, install the dependencies in the order are written + +### Basic libraries ``` -$ sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -[Press enter when prompted] -$ sudo apt-get update +sudo apt update +sudo apt install git build-essential libgtk2.0-dev pkg-config ``` -#### Downloading and Installing base dependencies -The first on the install list (and most important) is CMake, followed by git, C++ and various multimedia packages. -The following terminal command will get and install the necessary requirements +### CMAKE ``` -$ sudo apt-get install cmake git build-essential libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libavfilter-dev libx264-dev libx265-dev libvpx-dev liblzma-dev libbz2-dev libva-dev libvdpau-dev +wget https://cmake.org/files/v3.11/cmake-3.11.4-Linux-x86_64.sh +sudo mkdir /opt/cmake$ sudo sh cmake-3.11.4-Linux-x86_64.sh --prefix=/opt/cmake --skip-license +sudo update-alternatives --install /usr/bin/cmake cmake /opt/cmake/bin/cmake 1 --force ``` -#### Downloading and Installing the OpenCV libraries -The next step is to download and install the OpenCV libraries. -The necessary OpenCV library comes in two components. First download the core OpenCV library. Choose any directory as your download destination directory. -Clone OpenCV from Git as follows: +### C and C++ + +The C and C++ libraries from Ubuntu's official repositories are older than the libraries required. It's needed to have the C and C++ from version 6.3 or newer. + +#### Install the repository with the updated versions of C and C++ +``` +sudo add-apt-repository ppa:ubuntu-toolchain-r/test +sudo apt update ``` -$ cd `your_chosen_working_directory` -$ git clone https://github.com/opencv/opencv +#### C Libraries installation ``` -Next, repeat the process for the Extra modules. Remain in the same working directory and execute the following terminal command: +sudo apt install gcc-7 +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-7 --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-7 --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-7 +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 60 --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-5 --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-5 --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-5 +``` + +#### C++ Libraries installation ``` -$ git clone https://github.com/opencv/opencv_contrib +sudo apt install g++-7 +sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 60 ``` -You should now have two folders in your working directory. -The next step is to build OpenCV. -#### Building the OpenCV library -Your Chosen directory now contains two folders, opencv and opencv_contrib. The opencv folder contains the main OpenCV libraries and opencv_contib contains the extra modules. +### Install FFMPEG 3 +#### FMPEG Main appllication ``` -$ cd `your_chosen_working_directory` +sudo add-apt-repository ppa:jonathonf/ffmpeg-3 +sudo apt update +sudo apt install ffmpeg ``` -Inside the main OpenCV folder, change directory into the build folder (create one if it does not exist) and remove all files, since it will require rebuilding. To rebuild OpenCV run the following command from within the build folder: +#### FFMPEG Development libraries ``` -$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. +sudo apt install libavcodec-dev libavformat-dev libavfilter-dev +sudo apt install libx265-dev libx264-dev libvpx-dev libbz2-dev libvdpau-dev libva-dev liblzma-dev ``` -This step will generate a MakeFile. Once complete perform the following command to run make faster (the number after the j-flag is the number of processors the job will use). If you are not sure how many processors the machine has use the following instruction to find out: +## Installation of Track4K + +#### Clone the repositories: ``` -cat/proc/cpuinfo | grep processor | wc -l +git clone https://github.com/opencv/opencv +git clone https://github.com/opencv/opencv_contrib +git clone https://github.com/cilt-uct/trackhd.git ``` -Use the result from this in the j-flag +#### Install OpenCV + +> **Note: Track 4K works with version 3.4 of OpenCV, prerelease of V4.0 makes compilation errors.** + +In the OpenCV directory, Change to the 3.4 branch, next, build the program ``` -$ make -j`processor_count` +cd opencv +git checkout --track remotes/origin/3.4 +mkdir build +cd build +cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. ``` -Remain in the build folder and run the following cmake command to make the extra modules. -The path decribed below is an example. Fill in the directory path on your machine which points to the OpenCV Extra modules folder. +Once complete perform the following command to run make faster (the number after the j-flag is the number of processors the job will use). If you are not sure how many processors the machine has use the following instruction to find out: ``` -cmake -DOPENCV_EXTRA_MODULES_PATH=`OpenCV_Extra_Modules_Folder_Path`/modules ../ +cat /proc/cpuinfo | grep processor | wc -l ``` -Next step is to make these files: + +Use the result from this in the j-flag ``` -$ make -j8 +make -j`processor_count` ``` -Finally, install these modules by running the following command: +Remain in the build folder and run the following cmake command to make the extra modules. The path described below is an example. Fill in the directory path on your machine which points to the OpenCV Extra modules folder. + ``` -$ sudo make install +cmake -DOPENCV_EXTRA_MODULES_PATH=/opencv_contrib/modules ../ ``` + +After that compile and install the files: + +``` +make -j`processor_count` +sudo make install +``` + #### Building Track4K ##### Automatic Method -There is a shell script in the trackhd folder called intall_track4k.sh which can be used to install track4k automatically. +There is a shell script in the trackhd folder called `install_track4k.sh` which can be used to install track4k automatically. To use this script run the following command: ``` @@ -107,12 +150,13 @@ This will run all the steps listed in the manual method mentioned below. This method is for the case where the automatic method does not work. It does everything the shell script does manually. -The trackhd directory should have 2 main folders inside it: source and build. The source folder comntains all the header and source files while the build file contains all object files and executables. +The trackhd directory should have 2 main folders inside it: source and build. The source folder contains all the header and source files while the build file contains all object files and executables. The first step is to navigate into the build folder. Once inside run delete all files (if any) and then type the following command in terminal: ``` cmake ../source ``` + Now it is possible to run the build instruction: ``` @@ -134,15 +178,15 @@ cp cropvid /usr/local/bin/ #### Running Track4K -Track4K runs in two parts: track4k analyzes a video file and produces a cropping data file in text format. cropvid crops the +Track4K runs in two parts: track4k analyses a video file and produces a cropping data file in text format. cropvid crops the video file according to the cropping information in the data file, using ffmpeg libraries. ``` -$ track4k -$ cropvid +track4k +cropvid ``` -Example: +**Example:** ``` track4k presenter.mkv presenter-crop.txt 1920 1080 @@ -165,7 +209,8 @@ The program reads a maximum of 29 frames into memory at a time. So a minimum of ## Built With -* [OpenCV](http://www.opencv.org) - The computer vision library of choice +[OpenCV](http://www.opencv.org) - The computer vision library of choice +[FFFMPEG](https://www.ffmpeg.org) - A complete, cross-platform solution to record, convert and stream audio and video. ## License diff --git a/examples/galicaster/conf.ini b/examples/galicaster/conf.ini new file mode 100644 index 0000000..a90a080 --- /dev/null +++ b/examples/galicaster/conf.ini @@ -0,0 +1,32 @@ +# Galicaster configuration for recording 4K video from Axis 1428 IP camera for Track4K +# https://github.com/teltek/Galicaster/issues/459 +# Requires Galicaster 2.1.0 or later + +[basic] +custom_flavors=presenter4k + +[track1] +name = audio +device = pulse +flavor = presenter +location = alsa_input.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo +file = audio.flac +vumeter = True +amplification = 1.0 +player = True +audioencoder = deinterleave name=d d.src_0 ! audioconvert ! flacenc +active = True +delay = 0.2 + +[track2] +name = presenter +device = rtp +flavor = presenter4k +location = rtspt://VENUE-cam01.uct.ac.za/axis-media/media.amp +file = presenter.mkv +cameratype = h264 +audio = False +muxer = matroskamux +caps-preview = video/x-raw,framerate=1/1 +active = True + diff --git a/examples/opencast/ingest-track4k.xml b/examples/opencast/ingest-track4k.xml new file mode 100644 index 0000000..68c8533 --- /dev/null +++ b/examples/opencast/ingest-track4k.xml @@ -0,0 +1,42 @@ + + + + + + /opt/opencast/wfexec/track4k.pl + #{in} #{out} ${event_location} + presenter4k/source + true + tracked.mkv + presenter/source + archive + Track + 2.0 + + + + + + + */* + +archive + + + + + + + presenter4k/source + -archive + + + diff --git a/examples/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg b/examples/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg new file mode 100644 index 0000000..2e4a3e7 --- /dev/null +++ b/examples/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg @@ -0,0 +1,10 @@ +# Sample configuration for Opencast Execute Service + +# Load factor +job.load.execute = 1.0 + +# The list of commands, separated by spaces, which may be run by the Execute Service. +# A value of * means any command is allowed. +# Default: empty (no commands allowed) +commands.allowed = /opt/opencast/wfexec/track4k.pl + diff --git a/examples/opencast/track4k.json b/examples/opencast/track4k.json new file mode 100644 index 0000000..c5b03a9 --- /dev/null +++ b/examples/opencast/track4k.json @@ -0,0 +1,7 @@ +{ + "em4": { "output-size": "1080p" }, + "m209": { "output-size": "1620p" }, + "hoerilt1": { "output-size": "1080p", "y_top" : 650 }, + "hoerilt2": { "output-size": "1080p", "y_top" : 750 }, + "nlt": { "output-size": "720p" } +} diff --git a/examples/opencast/track4k.pl b/examples/opencast/track4k.pl new file mode 100755 index 0000000..1d2be39 --- /dev/null +++ b/examples/opencast/track4k.pl @@ -0,0 +1,82 @@ +#! /usr/bin/perl + +use strict; + +use WWW::Mechanize; +use Time::Local; +use JSON; + +my $track4k_bin = "/usr/local/bin/track4k"; +my $cropvid_bin = "/usr/local/bin/cropvid"; +my $track4k_cfg = "/opt/opencast/wfexec/track4k.json"; + +my $track_in = $ARGV[0]; +my $track_out = $ARGV[1]; +my $location = $ARGV[2]; + +die "\nSyntax:\n $0 input-file output-file [location]\n\n" if (!defined($track_in) || !defined($track_out)); + +system("/usr/bin/logger","track4k in=$track_in out=$track_out location='$location'") == 0 or die "Cannot log params: $?"; + +my $json = "{}"; + +if (-e $track4k_cfg) { + local $/; #Enable 'slurp' mode + open my $fh, "<", $track4k_cfg; + $json = <$fh>; + close $fh; + # print "JSON config: $json\n"; +} + +my $data = decode_json($json); + +# Default resolution +(my $out_x, my $out_y) = (1920, 1080); + +my $y_top; + +# Set parameters from config +if (defined($data->{$location})) { + my $output_size = $data->{$location}->{'output-size'}; + $y_top = $data->{$location}->{'y_top'}; + + if (defined($output_size)) { + if ($output_size eq "720p") { + ($out_x, $out_y) = (1280, 720); + } + if ($output_size eq "1620p") { + ($out_x, $out_y) = (2880, 1620); + } + } + # print "Config for $location output-size $output_size out-x $out_x out-y $out_y\n"; +} + +# Cropping data +my $cropdata = "/tmp/track4k-$$-crop.txt"; + +# Redirect stdout and stderr +my $system_stdout = "/tmp/track4k-$$-stdout.log"; +my $system_stderr = "/tmp/track4k-$$-stderr.log"; + +open(STDOUT, ">$system_stdout"); +open(STDERR, ">$system_stderr"); + +# Run Track4K +if (defined($y_top)) { + my @args = ($track4k_bin, $track_in, $cropdata, $out_x, $out_y, $y_top); + system(@args) == 0 or die "executing @args failed: $?"; +} else { + my @args = ($track4k_bin, $track_in, $cropdata, $out_x, $out_y); + system(@args) == 0 or die "executing @args failed: $?"; +} + +# Run cropvid +my @args = ($cropvid_bin, $track_in, $track_out, $cropdata); +system(@args) == 0 or die "executing @args failed: $?"; + +# Clean up +unlink($cropdata); +unlink($system_stdout); +unlink($system_stderr); + +exit 0; diff --git a/utils/Ansible_Playbook/group_vars/trackhd_clients b/utils/Ansible_Playbook/group_vars/trackhd_clients new file mode 100644 index 0000000..4614cbf --- /dev/null +++ b/utils/Ansible_Playbook/group_vars/trackhd_clients @@ -0,0 +1,5 @@ +#TrackHD Server parameters +trackhd_ip: CHANGE_ME +trackhd_port: CHANGE_ME +Log_file_client: output.log +Log_folder_client: /var/log/pyro4trackhd diff --git a/utils/Ansible_Playbook/group_vars/trackhd_server b/utils/Ansible_Playbook/group_vars/trackhd_server new file mode 100644 index 0000000..e2e852e --- /dev/null +++ b/utils/Ansible_Playbook/group_vars/trackhd_server @@ -0,0 +1,25 @@ +# TrackHD options + +### Pre-production and Development environments +# name of the NAS volume +nfs_name: CHANGE_ME + +# mount point for the NAS shared file system +## Same mount point of the opencast installation +fstab_name: CHANGE_ME + + + +### General Options + +#TrackHD Parameters + +server_user: CHANGE_ME +user_gid: CHANGE_ME +user_uid: CHANGE_ME + + +trackhd_repo: https://github.com/mliradelc/trackhd.git +trackhd_installation_path: /etc +trackhd_data_path: /etc +trackhd_port: CHANGE_ME diff --git a/utils/Ansible_Playbook/hosts b/utils/Ansible_Playbook/hosts new file mode 100644 index 0000000..8560583 --- /dev/null +++ b/utils/Ansible_Playbook/hosts @@ -0,0 +1,9 @@ +# In this file add the clients and the server of TrackHD + + +[trackhd_server] +#Insert IP or URL of the server below + + +[trackhd_clients] +#Insert IPs or URLs of the clients below diff --git a/utils/Ansible_Playbook/readme.md b/utils/Ansible_Playbook/readme.md new file mode 100644 index 0000000..21e78f9 --- /dev/null +++ b/utils/Ansible_Playbook/readme.md @@ -0,0 +1,19 @@ +# Ansible TrackHD Playbook + +This folder has the files you need to install TrackHD server and the comunication with Opencast. To use it first you need to have installed Ansible in the computer that will execute the orders to the remote hosts. + + +* In the `groups_vars` folder, modify the files according your existing setup. +* Add the URLs or IPs addresses for the clients and the server. + + +Enter to the folder and run the command in the terminal: + +``` +ansible-playbook -vv -i hosts trackhd_srv.yml -u --ask-sudo-pass + +ansible-playbook -vv -i hosts trackhd_clnt.yml -u --ask-sudo-pass +``` + + +Ansible will install TrackHD without hassle. diff --git a/utils/Ansible_Playbook/roles/track4k_client/files/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg b/utils/Ansible_Playbook/roles/track4k_client/files/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg new file mode 100644 index 0000000..a48de37 --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_client/files/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg @@ -0,0 +1,9 @@ +# Load factor +# Default: 0.1 +# Note that the load on the system will depend on which command is executed... +job.load.execute = 1.0 + +# The list of commands, separated by spaces, which may be run by the Execute Service. +# A value of * means any command is allowed. +# Default: empty (no commands allowed) +commands.allowed = /etc/opencast/trackhd_client.py diff --git a/utils/Ansible_Playbook/roles/track4k_client/tasks/main.yml b/utils/Ansible_Playbook/roles/track4k_client/tasks/main.yml new file mode 100644 index 0000000..8058da6 --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_client/tasks/main.yml @@ -0,0 +1,37 @@ +- name: Install pyhton 3 and PiP + yum: + name: "{{ item }}" + state: latest + with_items: + - python34 + - python34-pip + tags: trackhd_client + +- name: Install Pyro4 and Argparse libraries + pip: + executable: pip3.4 + name: "{{ item }}" + state: latest + with_items: + - Pyro4 + - argparse + tags: trackhd_client + +- name: Copy trackhd_client to the admin and worker nodes + template: + src: "templates/trackhd_client.py.j2" + dest: "/etc/opencast/trackhd_client.py" + mode: "755" + tags: trackhd_client-scripts + +- name: Allow trackhd_client.py to be run by opencast + copy: + src: "files/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg" + dest: "/etc/opencast/org.opencastproject.execute.impl.ExecuteServiceImpl.cfg" + tags: trackhd_client-execute + +- name: Create Log file folder + file: + path: "{{ Log_folder_client }}" + state: directory + mode: 775 diff --git a/utils/Ansible_Playbook/roles/track4k_client/templates/trackhd_client.py.j2 b/utils/Ansible_Playbook/roles/track4k_client/templates/trackhd_client.py.j2 new file mode 100644 index 0000000..d669e6e --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_client/templates/trackhd_client.py.j2 @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# Track4k Script to execute Track4K and cropvid from a +# remote machine. For Opencast execution +# Author: Maximiliano Lira Del Canto | RRZK University of Cologne, Germany + + +import sys +import Pyro4 +import Pyro4.util +import argparse +import logging +import sys + + +sys.excepthook = Pyro4.util.excepthook + +parser = argparse.ArgumentParser(description='Executes track4K and cropvid in a remote machine') + +#Argparsers arguments and description + +parser.add_argument('input_file', type=str, + help ='Input filename') + +parser.add_argument('output_file', type=str, + help='Name of the output file') + +parser.add_argument('width_out', type=str, + help ='Output width of the video') + +parser.add_argument('height_out', type=str, + help ='Output height of the video') + +parser.add_argument('track_mode', type=str, choices=['txt', 'json'], + help='Mode of the tracking, txt mode: Track + Video Crop. json mode: Only Track in JSON format for use in applications that can use that info') + + +args = parser.parse_args() + + +class StreamToLogger(object): + """ + Fake file-like stream object that redirects writes to a logger instance. + """ + def __init__(self, logger, log_level=logging.INFO): + self.logger = logger + self.log_level = log_level + self.linebuf = '' + + def write(self, buf): + for line in buf.rstrip().splitlines(): + self.logger.log(self.log_level, line.rstrip()) + + def flush(self): + pass + +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', + filename="{{ Log_folder_client }}/{{ Log_file_client }}", + filemode='a' +) + +stdout_logger = logging.getLogger('STDOUT') +sl = StreamToLogger(stdout_logger, logging.INFO) +sys.stdout = sl + +stderr_logger = logging.getLogger('STDERR') +sl = StreamToLogger(stderr_logger, logging.ERROR) +sys.stderr = sl + + + + +# Configure IP and port of the TrackHD serverself. +uri = 'PYRO:trackhd.prototype@{{ trackhd_ip }}:{{ trackhd_port }}' +trackhd = Pyro4.Proxy(uri) + + +#Run the application +print("Track HD Client Started") +print("Server IP address: " + "{{ trackhd_ip }}") +print("Server Port address: " + "{{ trackhd_port }}") +print ("") +print('Input details:') +print('Input Filename: ' + args.input_file) +print('Output Filename: ' + args.output_file) +print('Desired tracking resolution: ' + args.width_out + 'x' + args.height_out) +print('Track output mode: ' + args.track_mode) + +app = trackhd +app.track4k(args.input_file, args.output_file, args.width_out, args.height_out, args.track_mode) diff --git a/utils/Ansible_Playbook/roles/track4k_server/handlers/main.yml b/utils/Ansible_Playbook/roles/track4k_server/handlers/main.yml new file mode 100644 index 0000000..0f6cd88 --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_server/handlers/main.yml @@ -0,0 +1,2 @@ +- name: reload systemctl + command: systemctl daemon-reload diff --git a/utils/Ansible_Playbook/roles/track4k_server/tasks/main.yml b/utils/Ansible_Playbook/roles/track4k_server/tasks/main.yml new file mode 100644 index 0000000..ab6835d --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_server/tasks/main.yml @@ -0,0 +1,198 @@ +# Insert here installation of procedures of +# track4k and cropvid for the server. + +- name: mount the shared nfs filesystem + mount: + src: "{{ nfs_name }}" + name: "{{ fstab_name }}" + fstype: nfs + opts: "intr,acl,nosuid" + state: mounted + ignore_errors: yes + tags: oc_nfs + +- name: Create a new group user + group: + name: {{ server_user }} + gid: {{ user_gid }} + tags: oc_prepare + +- name: Create a new user user + user: + name: {{ server_user }} + uid: {{ user_uid }} + group: {{ server_user }} + tags: oc_prepare + +- name: Install basic libraries + apt: + name: "{{ item }}" + state: latest + update_cache: yes + with_items: + - git + - build-essential + - libgtk2.0-dev + - pkg-config + tags: trackhd_install-basic_libs + +- name: download and install cmake + block: + - name: Download CMAKE + command: wget https://cmake.org/files/v3.11/cmake-3.11.4-Linux-x86_64.sh + args: + chdir: /home/{{ server_user }} + - name: Create a folder to install CMAKE + file: + path: /opt/cmake + state: directory + mode: 755 + - name: Install CMAKE + command: sh cmake-3.11.4-Linux-x86_64.sh --prefix=/opt/cmake --skip-license + args: + chdir: /home/{{ server_user }} + - name: Update ENV variables to use CMAKE + command: update-alternatives --install /usr/bin/cmake cmake /opt/cmake/bin/cmake 1 --force + tags: trackhd_install-cmake + +- name: download and install latest versions of C and C++ + block: + - name: Adding ubuntu-toolchain-r/test repository for GCC 7 and G++ 7 + apt_repository: + repo: ppa:ubuntu-toolchain-r/test + - name: Downloading GCC 7 + apt: + name: gcc-7 + - name: Update ENV variables to use gcc 7 + command: update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-7 --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-7 --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-7 + - name: Update ENV variables of gcc 5 + command: update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 60 --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-5 --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-5 --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-5 + - name: Intalling G++ 7 + apt: + name: g++-7 + - name: Update ENV variables to use G++ 7 + command: update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 60 + tags: trackhd_install-gcc + +- name: Install FFMPEG 3 + block: + - name: Adding jonathonf/ffmpeg-3 repository + apt_repository: + repo: ppa:jonathonf/ffmpeg-3 + - name: Installing ffmpeg + ffmpeg dev libraries + apt: + name: "{{ item }}" + with_items: + - ffmpeg + - libavcodec-dev + - libavformat-dev + - libavfilter-dev + - libx265-dev + - libx264-dev + - libvpx-dev + - libbz2-dev + - libvdpau-dev + - libva-dev + - liblzma-dev + tags: trackhd_install-ffmpeg + + +- name: Clone git repositories of OpenCV and TrackHD + block: + - name: Cloning Opencv 3.4 repository + git: + repo: https://github.com/opencv/opencv.git + dest: /home/{{ server_user }}/opencv + version: 3.4 + - name: Cloning Opencv_contrib repository + git: + repo: https://github.com/opencv/opencv_contrib.git + dest: /home/{{ server_user }}/opencv_contrib + version: 3.4 + - name: Cloning TrackHD repository + git: + repo: "{{ trackhd_repo }}" + dest: /home/{{ server_user }}/trackhd + tags: trackhd_install-git + +- name: Install opencv + block: + - name: Create build folder for OpenCV + file: + path: /home/{{ server_user }}/opencv/build + state: directory + - name: Run CMAKE for OpenCV + command: cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. + args: + chdir: /home/{{ server_user }}/opencv/build + - name: Get number of logic CPUs in the machine + shell: cat /proc/cpuinfo | grep processor | wc -l + register: proc_count + - name: Building OpenCV + make: + chdir: /home/{{ server_user }}/opencv/build + params: + NUM_THREADS: "{{ proc_count }}" + - name: Adding Opencv_contrib modules + command: cmake -DOPENCV_EXTRA_MODULES_PATH=/home/{{ server_user }}/opencv_contrib/modules ../ + args: + chdir: /home/{{ server_user }}/opencv/build + - name: Building OpenCV with the Opencv_contrib modules + make: + chdir: /home/{{ server_user }}/opencv/build + params: + NUM_THREADS: "{{ proc_count }}" + - name: Installing the building of OpenCV to the system + command: make install + args: + chdir: /home/{{ server_user }}/opencv/build + tags: trackhd_install-opencv + +- name: Install Track4K + command: sh ./install_track4k.sh + args: + chdir: /home/{{ server_user }}/trackhd + +- name: Install pyhton 3 and PiP + apt: + name: "{{ item }}" + state: latest + with_items: + - python3 + - python3-pip + tags: trackhd_script_libs + +- name: Install Pyro4 and Argparse libraries + pip: + executable: pip3 + name: "{{ item }}" + state: latest + with_items: + - Pyro4 + - argparse + tags: trackhd_script_libs + +- name: Register libraries to the system + command: ldconfig -v + tags: + - trackhd_install-basic_libs + - trackhd_install-opencv + - trackhd_install-ffmpeg + +- name: Copy trackhd_server to desired machine + template: + src: "templates/trackhd_server.py.j2" + dest: /etc/trackhd_server.py + mode: "755" + tags: trackhd_install + +- name: TrackHD | Create Unit file + template: + src: "templates/trackhd.service.j2" + dest: /lib/systemd/system/trackhd.service + mode: "644" + notify: + - reload systemctl + +- name: TrackHD | Start TrackHD Server as a service + service: name=trackhd.service state=started enabled=yes diff --git a/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd.service.j2 b/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd.service.j2 new file mode 100644 index 0000000..e9e5bc5 --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd.service.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Track HD Server +Requires=network.target +After=syslog.target network.target + +[Service] +Type=simple +User={{ server_user }} +Group={{ server_user }} +WorkingDirectory=/etc/ +ExecStart={{ trackhd_installation_path }}/trackhd_server.py +StandardOutput=syslog +StandardError=syslog + + +[Install] +WantedBy=multi-user.target diff --git a/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd_server.py.j2 b/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd_server.py.j2 new file mode 100644 index 0000000..0611100 --- /dev/null +++ b/utils/Ansible_Playbook/roles/track4k_server/templates/trackhd_server.py.j2 @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Track4k Script to execute Track4K and cropvid from a +# remote machine. To run in a standalone server (With Track4K and Cropvid installed). +# Author: Maximiliano Lira Del Canto | RRZK University of Cologne, Germany + + + +import Pyro4 +import subprocess +import os + +@Pyro4.expose +@Pyro4.behavior(instance_mode = 'single') +class trackhd: + + def cropvid(self, input_file, output_file, track_file): + cmd = ['/usr/local/bin/cropvid', input_file, output_file, track_file] + print('Cropping file, please wait...') + print('Input details:') + print('Input Filename: ' + input_file) + print('Output Filename: ' + output_file) + print('Track File: ' + track_file) + while True: + app = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE) + if app.returncode == 0: + break + return [app.returncode, app.stdout] + + def track4k(self, input_file, output_file, width, height, mode): + print('Tracking File, please wait...') + print('Input details:') + print('Input Filename: ' + input_file) + print('Output Filename: ' + output_file) + print('Desired tracking resolution: ' + width + 'x' + height) + print('Track output mode: ' + mode) + if mode == 'txt': + output_track = output_file + '.txt' + else: + output_track = output_file + cmd = ['/usr/local/bin/track4k', input_file, output_track, width, height] + while True: + print('Processing video') + app = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE) + print(app.stdout) + if app.returncode == 0: + break + if mode == 'txt': + print('Executing Cropvid') + self.cropvid(input_file, output_file, output_track) + print('Crop succesfull, output file: ' + output_file) + return [app.returncode, app.stdout] + + + +# def getNS(): +# """ +# Return a Pyro name server proxy. If there is no name server running, +# start one on 0.0.0.0 (all interfaces), as a background process. +# +# """ +# import Pyro4 +# try: +# return Pyro4.locateNS() +# except Pyro4.errors.NamingError: +# print("Pyro name server not found; starting a new one") +# os.system("python3 -m Pyro4.naming -n 0.0.0.0 -p 15236 &") +# # TODO: spawn a proper daemon ala http://code.activestate.com/recipes/278731/ ? +# # like this, if there's an error somewhere, we'll never know... (and the loop +# # below will block). And it probably doesn't work on windows, either. +# while True: +# try: +# return Pyro4.locateNS() +# except: +# pass + +def main(): + +# getNS() + + Pyro4.Daemon.serveSimple( + { + trackhd: "trackhd.prototype" + }, + host = '0.0.0.0', + port = {{ trackhd_port }}, + ns = False) + +if __name__=="__main__": + main() + + +#app = trackhd() +#app.track4k(input_file='/mnt/opencast/4k_sample/presenter.mkv',output_file='/mnt/opencast/4k_sample/tracked.mkv',width='1920', height='1080', mode='json') diff --git a/utils/Ansible_Playbook/trackhd_clnt.yml b/utils/Ansible_Playbook/trackhd_clnt.yml new file mode 100644 index 0000000..cf89592 --- /dev/null +++ b/utils/Ansible_Playbook/trackhd_clnt.yml @@ -0,0 +1,6 @@ +- hosts: trackhd_clients + become: yes + become_method: sudo + become_user: root + roles: + - track4k_client diff --git a/utils/Ansible_Playbook/trackhd_srv.yml b/utils/Ansible_Playbook/trackhd_srv.yml new file mode 100644 index 0000000..d87da8b --- /dev/null +++ b/utils/Ansible_Playbook/trackhd_srv.yml @@ -0,0 +1,6 @@ +- hosts: trackhd_server + become: yes + become_method: sudo + become_user: root + roles: + - track4k_server diff --git a/utils/Track4KPyro/trackhd.service b/utils/Track4KPyro/trackhd.service new file mode 100644 index 0000000..37385c8 --- /dev/null +++ b/utils/Track4KPyro/trackhd.service @@ -0,0 +1,17 @@ +[Unit] +Description=Track HD Server +Requires=network.target +After=syslog.target network.target + +[Service] +Type=simple +User={{ server_user }} +Group={{ server_user }} +WorkingDirectory=/etc/ +ExecStart=/usr/bin/python3 -u {{ trackhd_installation_path }}/trackhd_server.py +StandardOutput=syslog +StandardError=syslog + + +[Install] +WantedBy=multi-user.target diff --git a/utils/Track4KPyro/trackhd_client.py b/utils/Track4KPyro/trackhd_client.py new file mode 100644 index 0000000..69428f6 --- /dev/null +++ b/utils/Track4KPyro/trackhd_client.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Track4k Script to execute Track4K and cropvid from a +# remote machine. For Opencast execution +# Author: Maximiliano Lira Del Canto | RRZK University of Cologne, Germany + + +import sys +import Pyro4 +import Pyro4.util +import argparse +import logging +import sys + +#Please Change this values before the first run +trackhd_ip = 'CHANGE_ME' +trackhd_port = 'CHANGE_ME' +log_file = 'CHANGE_ME' + +# Pyro 4 Exceptbook: Sends error messages from Server to client +sys.excepthook = Pyro4.util.excepthook + +parser = argparse.ArgumentParser(description='Executes track4K and cropvid in a remote machine') + +#Argparsers arguments and description + +parser.add_argument('input_file', type=str, + help ='Input filename') + +parser.add_argument('output_file', type=str, + help='Name of the output file') + +parser.add_argument('width_out', type=str, + help ='Output width of the video') + +parser.add_argument('height_out', type=str, + help ='Output height of the video') + +parser.add_argument('track_mode', type=str, choices=['txt', 'json'], + help='Mode of the tracking, txt mode: Track + Video Crop. json mode: Only Track in JSON format for use in applications that can use that info') + + +args = parser.parse_args() + + +# Class to create logfiles in the client machine +class StreamToLogger(object): + """ + Fake file-like stream object that redirects writes to a logger instance. + """ + def __init__(self, logger, log_level=logging.INFO): + self.logger = logger + self.log_level = log_level + self.linebuf = '' + + def write(self, buf): + for line in buf.rstrip().splitlines(): + self.logger.log(self.log_level, line.rstrip()) + + def flush(self): + pass + +# Log file store location, change it or configure linux to make it work in that location +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', + filename= log_file, + filemode='a' +) + +stdout_logger = logging.getLogger('STDOUT') +sl = StreamToLogger(stdout_logger, logging.INFO) +sys.stdout = sl + +stderr_logger = logging.getLogger('STDERR') +sl = StreamToLogger(stderr_logger, logging.ERROR) +sys.stderr = sl + + + + +# Configure IP and port of the TrackHD server. +uri = 'PYRO:trackhd.prototype@' + trackhd_ip +':'+ trackhd_port +trackhd = Pyro4.Proxy(uri) + + +#Run the application +print("Track HD Client Started") +print("Server IP address: " + trackhd_ip) +print("Server Port address: " + trackhd_port) +print (" ") +print('Input details:') +print('Input Filename: ' + args.input_file) +print('Output Filename: ' + args.output_file) +print('Desired tracking resolution: ' + args.width_out + 'x' + args.height_out) +print('Track output mode: ' + args.track_mode) + +app = trackhd +app.track4k(args.input_file, args.output_file, args.width_out, args.height_out, args.track_mode) diff --git a/utils/Track4KPyro/trackhd_server.py b/utils/Track4KPyro/trackhd_server.py new file mode 100644 index 0000000..2e51efd --- /dev/null +++ b/utils/Track4KPyro/trackhd_server.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Track4k Script to execute Track4K and cropvid from a +# remote machine. To run in a standalone server (With Track4K and Cropvid installed). +# Author: Maximiliano Lira Del Canto | RRZK University of Cologne, Germany + + + +import Pyro4 +import subprocess +import os + +#Please Change this value before the first run +# trackhd_port is an int. +trackhd_port = 'CHANGE_ME' + + + +# Expose the trackhd class throught Pyro4 interface +@Pyro4.expose +@Pyro4.behavior(instance_mode = 'single') +class trackhd: + # Method to crop files + def cropvid(self, input_file, output_file, track_file): + cmd = ['/usr/local/bin/cropvid', input_file, output_file, track_file] + print('Cropping file, please wait...') + print('Input details:') + print('Input Filename: ' + input_file) + print('Output Filename: ' + output_file) + print('Track File: ' + track_file) + while True: + app = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE) + if app.returncode == 0: + break + return [app.returncode, app.stdout] + + # Method to create the track file for crop or for auto zoom in paella player + def track4k(self, input_file, output_file, width, height, mode): + print('Tracking File, please wait...') + print('Input details:') + print('Input Filename: ' + input_file) + print('Output Filename: ' + output_file) + print('Desired tracking resolution: ' + width + 'x' + height) + print('Track output mode: ' + mode) + if mode == 'txt': + output_track = output_file + '.txt' + else: + output_track = output_file + cmd = ['/usr/local/bin/track4k', input_file, output_track, width, height] + while True: + print('Processing video') + app = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE) + print(app.stdout) + if app.returncode == 0: + break + if mode == 'txt': + print('Executing Cropvid') + self.cropvid(input_file, output_file, output_track) + print('Crop succesfull, output file: ' + output_file) + return [app.returncode, app.stdout] + + + +def main(): + # Start of Pyro4 Server + Pyro4.Daemon.serveSimple( + { + trackhd: "trackhd.prototype" + }, + + # Allow connection from any IP of the server + host = '0.0.0.0', + port = trackhd_port, + ns = False) + +if __name__=="__main__": + main() + + +# Test lines, uncomment to Test the class without Pyro 4 +#app = trackhd() +#app.track4k(input_file='/mnt/opencast/4k_sample/presenter.mkv',output_file='/mnt/opencast/4k_sample/tracked.mkv',width='1920', height='1080', mode='json') diff --git a/utils/assets/Diagram-Track4K-Pyro4.png b/utils/assets/Diagram-Track4K-Pyro4.png new file mode 100644 index 0000000..e3e36c2 Binary files /dev/null and b/utils/assets/Diagram-Track4K-Pyro4.png differ diff --git a/utils/opencast_workflows/fast-4k.xml b/utils/opencast_workflows/fast-4k.xml new file mode 100644 index 0000000..90f440c --- /dev/null +++ b/utils/opencast_workflows/fast-4k.xml @@ -0,0 +1,175 @@ + + + + fast4k + Fast Test 4k Tracker system + + upload + + Test the Track4K implementation + + + +
+ Hint: Media Library is the standard publication channel and automatically selected +
+ +
+ Choose additional publication channels +
    +
  • + + +
  • +
  • + + +
  • +
  • + + + +
    + Choose layout for above selected channels (used if two video streams exist) +
      +
    • + + +
    • +
    • + + +
    • +
    +
    + +
  • +
+
+ +
+ 4K Video options +
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
+ +
+ Do you need to trim ? +
    +
  • + + +
  • +
+
+ + + + + + + + + + + ]]> +
+ + + + + + + + + false + false + false + false + 1 + false + false + + + + + + + + track4k + + + + + + + + +
diff --git a/utils/opencast_workflows/track4k.xml b/utils/opencast_workflows/track4k.xml new file mode 100644 index 0000000..e5ca7e3 --- /dev/null +++ b/utils/opencast_workflows/track4k.xml @@ -0,0 +1,90 @@ + + + + track4k + Track the presenter by cropping the 4K Video + + + + + + + + + + presenter/source + presenter4k/source + + + + + + + + + /etc/opencast/trackhd_client.py + #{flavor(presenter4k/source)} #{out} 1920 1080 txt + presenter4k/source + true + tracked.mkv + presenter/source + archive + Track + 2.0 + + + + + + + + /etc/opencast/trackhd_client.py + #{flavor(presenter4k/source)} #{out} 1920 1080 json + presenter/source + trackhd.json + presenter/trackhd + engage-download,engage-streaming,archive + Attachment + + + + + + + + */* + +archive + + + + + + + presenter4k/source + -archive + + + + + + diff --git a/utils/readme.md b/utils/readme.md new file mode 100644 index 0000000..c70559b --- /dev/null +++ b/utils/readme.md @@ -0,0 +1,107 @@ +# Track4K Utilities + +In this folder you can find different utilities to work with Track4K, the utilities available at the moment are: + +* **Track4KPyro** : Python3 script built with Pyro4 to execute remotely Track4K by using remote objects in a Client/Server Scheme. +* **opencast_workflows** : Samples of workflows to work with the scripts. +* **Ansible Playbooks** : An Ansible playbook to install TrackHD automatically with the **Track4KPyro** server script included. + + +## Track4KPyro + +The idea behind Track4KPyro is because Track4K and cropvid were built to work in Ubuntu systems and it was need to run this programs over other Linux machines like CentOS or Debian based systems. + +Track4KPyro makes possible to work with any other machine without installing dependencies not supported officially for the distribution or making custom builds that might be very troublesome. + +One of the uses of Track4KPyro is to be part of an Opencast workflow as an external script. Here is a diagram about how works with Opencast: + +![Track4K-Pyro4-Diagram](/utils/assets/Diagram-Track4K-Pyro4.png) + +### Installation + +Simply you need to install this dependencies in each machine, for opencast users: this includes all the workers and the admin: + +* Python 3 or newer +* Argparse and Pyro4 libraries (Can be installed using PiP for Python 3) + +**Important:** Before the first execution, you need to check: + +* If you use with an NFS share, you need to use the same username, group, *uid* and *gid* of the same user that will work with the processed assets. + +#### In the machine with track4K and cropvid installed: + +* Copy and execute `trackhd_server-py`, you should see this in the terminal: + +``` +Object : + + uri = PYRO:trackhd.prototype@0.0.0.0: +Pyro daemon running. +``` +\* The port and the IP from what accept the clients can be changed in the code. + +* Allow inbound TCP connection throught the port + + +**If you installed Track HD as a Systemd service, like in the included ansible playbook, you can run it using this line:** + +```bash +# systemctl start trackhd +``` + +#### In the client machine: + +* Set the *IP*, and *Port* of the machine that has `trackhd_server.py`running inside the `trackhd_client.py` script. +* for Opencast users: + - Allow the client script to be executed by adding in the Execute bundle configuration file `org.opencastproject.execute.impl.ExecuteServiceImpl.cfg` *In each worker and admin node*. + - Install the dependencies and the client script *In each worker and admin node*. + - Install or configure the scripts to use the `Execute-Once` or `Execute-many` WOH + +### Usage +The options to use in `trackhd_client.py` are: + +``` +usage: trackhd_client.py [-h] + input_file output_file width_out height_out + {txt,json} + +Executes track4K and cropvid in a remote machine + +positional arguments: + input_file Input filename + output_file Name of the output file + width_out Output width of the video + height_out Output height of the video + {txt,json} Mode of the tracking, txt mode: Track + Video Crop. json mode: + Only Track in JSON format for use in applications that can use that info + +optional arguments: + -h, --help show this help message and exit +``` + +### Known Issues: + +* If Opencast sends a non-video file to the execute service, the track HD server will enter to an infinite loop. +* Track HD server Syslog is not logging everything. + +### Future Work: + +* [x] Integrate *trackhd_server.py* as a OS service. +* [x] Log files generated from server and the client scripts +* [ ] Exception handling in case of problems. + +## Ansible playbooks + +Included in the [Utils folder](/utils/Ansible_Playbook), there is and Ansible Playbook that is ready to install Track HD with the Pyro4 script for the server side. + +**Important:** Take note this script is already in a *Ansible folder structure*. The variables and hosts had to be set before use. + +To execute, simply run, for the clients or the server: +``` +ansible-playbook -vv -i hosts [trackhd_clnt.yml | trackhd_srv.yml] -u [user_with_sudo] --ask-sudo-pass +``` + + +## Opencast Workflows + +This workflows for opencast are a samples they how will work with **Track4KPyro**, you only have to remember to install and allow this script in each admin and each worker node of opencast.