diff --git a/README.md b/README.md index e8d281a..89eb594 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ rffmpeg is a remote FFmpeg wrapper used to execute FFmpeg commands on a remote server via SSH. It is most useful in situations involving media servers such as Jellyfin (our reference user), where one might want to perform transcoding actions with FFmpeg on a remote machine or set of machines to better handle the load. -## Usage +## Quick usage -1. Install the required Python 3 dependencies: `yaml` and `subprocess`. +1. Install the required Python 3 dependencies `yaml` and `subprocess` (`sudo apt install python3-yaml python3-subprocess` in Debian). 1. Create the directory `/etc/rffmpeg`. @@ -12,14 +12,18 @@ rffmpeg is a remote FFmpeg wrapper used to execute FFmpeg commands on a remote s 1. Install `rffmpeg.py` somewhere useful, for instance at `/usr/local/bin/rffmpeg.py`. -1. Create symlinks for the command names `ffmpeg` and `ffprobe` to `rffmpeg.py`, for instance `/usr/local/bin/ffmpeg -> /usr/local/bin/rffmpeg.py` and `/usr/local/bin/ffprobe -> /usr/local/bin/rffmpeg.py`. +1. Create symlinks for the command names `ffmpeg` and `ffprobe` to `rffmpeg.py`, for example `sudo ln -s /usr/local/bin/rffmpeg.py /usr/local/bin/ffmpeg` and `sudo ln -s /usr/local/bin/rffmpeg.py /usr/local/bin/ffprobe`. -1. Edit your media program to use the `rffmpeg.py` binary (via the symlink names) instead of the standard `ffmpeg` binary. +1. Set your media program to use `rffmpeg.py` via the symlink names created above, instead of any other `ffmpeg` binary. 1. Profit! +For a more detailed setup guide, see the section "Full setup guide" below. + ## rffmpeg options and caveats +The `rffmpeg.yml.sample` is self-documented for the most part. Some additional important information you might need is presented below. + ### Remote hosts rffmpeg supports setting multiple hosts. It keeps state in `/run/shm/rffmpeg`, of all running processes. These state files are used during rffmpeg's initialization in order to determine the optimal target host. rffmpeg will run through these hosts sequentially, choosing the one with the fewest running rffmpeg jobs. This helps distribute the transcoding load across multiple servers, and can also provide redundancy if one of the servers is offline - rffmpeg will detect if a host is unreachable and set it "bad" for the remainder of the run, thus skipping it until the process completes. @@ -42,15 +46,15 @@ When running rffmpeg manually, *do not* exit it with `Ctrl+C`. Doing so will lik ## Full setup guide -This example setup is the one I use for `rffmpeg`, involving a media server (`jf1`) and a remote transcode server (`gpu1`). Both systems run Debian GNU/Linux, though the commands below should also work on Ubuntu. Note that Docker is not officially supported with `rffmpeg` due to the complexity of exporting Docker volumes with NFS, the path differences, and the fact that I don't use Docker, but if you do figure it out a PR is welcome. +This example setup is the one I use for `rffmpeg` with Jellyfin, involving a media server (`jf1`) and a remote transcode server (`gpu1`). Both systems run Debian GNU/Linux, though the commands below should also work on Ubuntu. Note that Docker is not officially supported with `rffmpeg` due to the complexity of exporting Docker volumes with NFS, the path differences, and the fact that I don't use Docker, but if you do figure it out a PR is welcome. -1. Prepare the media server (`jf1`) with Jellyfin using the standard `.deb` install. Make note of main Jellyfin data path; it's usually `/var/lib/jellyfin` unless you change it. Note that if you change this path, or put the various subdirectories such as the `transcodes` or `data/subtitles` directories elsewhere, you may need to alter the NFS steps below to accommodate this. +1. Prepare the media server (`jf1`) with Jellyfin using the standard `.deb` install. Make note of the main Jellyfin data path, usually `/var/lib/jellyfin` unless you change it. Note that if you change this path, or put the various subdirectories such as the `transcodes` or `data/subtitles` directories elsewhere, you may need to alter the NFS steps below to accommodate this. -1. On the media server, create an SSH keypair owned by the Jellyfin service user; save this SSH key somewhere readable to the service user: `sudo -u jellyfin mkdir -p /var/lib/jellyfin/.ssh && sudo -u jellyfin ssh-keygen -t rsa -f /var/lib/jellyfin/.ssh/id_rsa`. +1. On the media server, create an SSH keypair owned by the Jellyfin service user; save this SSH key somewhere readable to the service user: `sudo -u jellyfin mkdir -p -m 0700 /var/lib/jellyfin/.ssh && sudo -u jellyfin ssh-keygen -t rsa -f /var/lib/jellyfin/.ssh/id_rsa`. 1. Copy (or symlink) the new SSH public key created in the previous step to `authorized_keys`; this will be used later when the Jellyfin data directory is mounted on the transcode server: `sudo -u jellyfin cp -a /var/lib/jellyfin/.ssh/id_rsa.pub /var/lib/jellyfin/.ssh/authorized_keys` -1. Install the rffmpeg program as detailed in the above section, including creating the `/etc/rffmpeg/rffmpeg.yml` configuration file and symlinks. +1. Install the rffmpeg program as detailed in the "Quick usage" section above, including creating the `/etc/rffmpeg/rffmpeg.yml` configuration file and symlinks. 1. Install the NFS kernel server: `sudo apt -y install nfs-kernel-server` @@ -58,7 +62,7 @@ This example setup is the one I use for `rffmpeg`, involving a media server (`jf 1. On the transcode server, install any required tools or programs to make use of hardware transcoding; this is optional if you only use software (i.e. CPU) transcoding. -1. Install the `jellyfin-ffmpeg` package to provide an FFmpeg binary; follow the Jellyfin installation instructions for details on setting up the Jellyfin repository, though install only `jellyfin-ffmpeg`. +1. Install the `jellyfin-ffmpeg` package to provide an FFmpeg binary; follow the Jellyfin installation instructions for details on setting up the Jellyfin repository, though install only `jellyfin-ffmpeg`. While you can technically install any `ffmpeg` binary you wish, we recommend using Jellyfin's official `ffmpeg` for Jellyfin users to maximize compatibility. 1. Install the NFS client utilities: `sudo apt install -y nfs-common` @@ -68,15 +72,17 @@ This example setup is the one I use for `rffmpeg`, involving a media server (`jf 1. Mount the media server NFS data share at the same directory on the transcode server: `echo 'jf1:/var/lib/jellyfin /var/lib/jellyfin nfs defaults,vers=3,sync 0 0' | sudo tee -a /etc/fstab && sudo mount -a` -1. Mount your media directory on the transcode server at the same location as on the media server and using the same method; if your media is local to the media server, export it with NFS similarly to the data directory. +1. Mount your media directory on the transcode server at the same location as on the media server and using the same method; if your media is local to the media server, export it with NFS in addition to the data directory. 1. On the media server, attempt to SSH to the transcode server as the `jellyfin` user using the key from step 2; this both tests the connection as well as saves the transcode server SSH host key locally: `sudo -u jellyfin ssh -i /var/lib/jellyfin/.ssh/id_rsa jellyfin@gpu1` -1. Verify that rffmpeg itself works by calling its `ffmpeg` alias with the `-version` option: `sudo -u jellyfin /usr/local/bin/ffmpeg -version` +1. Repeat the above step for any additional host(s), if applicable. + +1. Verify that rffmpeg itself works by calling its `ffmpeg` alias as the service user with the `-version` option: `sudo -u jellyfin /usr/local/bin/ffmpeg -version` 1. In Jellyfin, set the rffmpeg binary, via its `ffmpeg` symlink, as your "FFmpeg path" in the Playback settings; optionally, enable any hardware encoding you configured in step 7. -1. Try running a transcode and verifying that the `rffmpeg` program works as expected. The flow should be: +1. Try running a transcode and verifying that the `rffmpeg` program works as expected by checking the log file specified in the `rffmpeg.yml` configuration. The flow should be: 1. Jellyfin calls rffmpeg with the expected arguments.