Readit News logoReadit News
Posted by u/steelbrain a year ago
Show HN: FFmpeg-over-IP – Connect to remote FFmpeg serversgithub.com/steelbrain/ffm...
Dear HN,

I’m excited to show case a personal project. It has helped me quite a bit with my home lab, I hope it can help you with yours too! ffmpeg-over-ip has two components, a server and a client. You can run the server in an environment with access to a GPU and a locally installed version of ffmpeg, the client only needs network access to the server and no GPU or ffmpeg locally.

Both and client and the server need a shared filesystem for this to work (so the server can write output to it, and client can read from it). In my usecase, smb works well if your (GPU) server is a windows machine, nfs works really well for linux setups.

This utility can be useful in a number of scenarios:

- You find passing through a (v)GPU to your virtual machines complicated

- You want to use the same GPU for ffmpeg in multiple virtual machines

- Your server has a weak GPU so you want to use the GPU from your gaming machine

- Your GPU drivers in one OS are not as good as another (AMD RX6400 never worked for me in linux, but did so in windows)

I’ve posted some instructions in the Github package README, please let me know if they are unclear in any way and I’ll try to help!

Here's the link: https://github.com/steelbrain/ffmpeg-over-ip

NavinF · a year ago
> need a shared filesystem for this to work

Oh oof. I thought removing that requirement would be the whole point of something named "FFmpeg-over-IP". Shared filesystem usually involves full trust between machines, bad network error handling, and setting things up by hand (different config on every distro)

steelbrain · a year ago
I hear you. If your usecase doesn't require live streaming of converted file, a sibling comment may fit the usecase: https://news.ycombinator.com/item?id=41745593
qwertox · a year ago
One could write a small Python server in one day which receives a chunked POST request and transcodes the video on the fly.

The same server could also offer a download link for the transcoded video, and also receive URL parameters for the transcoding options. Or the transcoded video itself is returned after the subprocess finishes.

Something along the lines of:

Server

  import asyncio
  import subprocess
  from aiohttp import web
  async def transcode_video(request):
      cmd = [
          "ffmpeg",
          "-i", "pipe:0",
          "-f", "mp4",
          "-preset", "fast",
          "output_file.mp4"
      ]
      process = await asyncio.create_subprocess_exec(
          *cmd,
          stdin=subprocess.PIPE,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE
      )
      async for chunk in request.content.iter_any():
          process.stdin.write(chunk)
          await process.stdin.drain()
      await process.stdin.close()
      await process.wait()
      return web.Response(text="Video transcoded successfully!")
  app = web.Application()
  app.router.add_post('/upload', transcode_video)
  if __name__ == '__main__':
      web.run_app(app, port=8080)
Client

  curl -X POST http://<server_ip>:8080/upload \
       --header "Content-Type: application/octet-stream" \
       --data-binary @video.mp4

This way no shared filesystem is required.

NavinF · a year ago
Ah unfortunately my use case is similar to yours: Use Windows desktop to transcode files stored on a Linux NAS. My files are ~100GB so encoding multiple files in parallel would waste a lot of space and unnecessarily burn write cycles
yarg · a year ago
Couldn't you create and share a virtual file system with FUSE?
NavinF · a year ago
Mounting anything requires root even if you use FUSE.

There are ways to intercept writes without root and send them to another machine. Eg you could use LD_PRELOAD. But that's exactly the kind of pain in the ass that I was hoping a project named FFmpeg-over-IP would automate.

yjftsjthsd-h · a year ago
Like SSHFS, or something custom? And how much does that help with any of those concerns?
steelbrain · a year ago
There is an existing solution in the community called rffmpeg[1] but that did not work for me. It seems too heavy weight for what I was trying to do. It requires access to sudo, global configuration files (/etc/) and most importantly, this, which is a deal-breaker for me:

> Note that if hardware acceleration is configured in the calling application, the exact same hardware acceleration modes must be available on all configured hosts, and, for fallback to work, the local host as well, or the ffmpeg commands will fail.

I wanted to mix and match windows and linux, and it was clear rffmpeg wasn't going to work for me.

One plus rffmpeg does have is that it supports multiple target hosts, so it's useful if you want some load balancing action. Although you could do the same with ffmpeg-over-ip, just selecting the servers dynamically but rffmpeg does make it easier out of the box.

[1]:https://github.com/joshuaboniface/rffmpeg

qwertox · a year ago
IDK, this lacks a lot of examples and explaining what exactly it is for. Is it for remote transcoding only?

Because if so, the word transcoding does not appear neither in this Show HN nor in the GitHub README.

And I can't think of any other use for this than to perform hardware-assisted transcoding on a remote machine.

Apparently it has nothing to do with OpenGL or CUDA, which are the primary uses for a GPU. And ffmpeg itself has more use cases than just transcoding files.

dylan604 · a year ago
I question for why not just SSH into the more powerful computer to run the ffmpeg command like a normal person. Why would you need to install a server and client? There are plenty of binaries available for ffmpeg to avoid compiling from source difficulties.

Solutions like these are the things that just make me tilt my head and make the clueless "huh?" sound.

oefrha · a year ago
Because OpenSSH on Windows is a shitshow. Mounted SMB shares can’t be accessed because they’re tied to login sessions, and you can’t mount them from within an SSH session (IIRC in theory you can, but in practice it never worked for me).[1] Which means ffmpeg is practically useless if you need input that you can’t (e.g. livestream) or don’t want to copy in advance, or need output in realtime.

At least that’s why I built something similar in Go for myself.

Before anyone mentions WSL: it either didn’t support GPU passthrough or was very difficult to configure when I set this up a few years ago, don’t know about current status. And you can’t call Windows executables from WSL when you SSH into it.

[1] https://github.com/PowerShell/Win32-OpenSSH/issues/139

maxlin · a year ago
I wrote something similar to this. Instead of requiring a shared network drive, dependent files are automatically detected and transferred over with HTTP, and as an advanced feature, it splits the video to chunks to allow 20x+ encode speeds, concurrently utilizing multiple machines to encode a single input file and utilizing NVENC. Video is then concatenated together and API for that mode is identical.

Wrote it in C# and it runs both on Windows and Linux. The original need for this actually was to accelerate encodes a system I run on a cloud VM needs when I have either my desktop or laptop available, who then work as encode slaves and pick up jobs, run them and send the output files back. If no slaves are available, the system falls back to local CPU encode. Later I ended up using this using a local Windows server machine as the "client" the slaves also connect to to ask for jobs (actually the system runs inside a Unity project in that case because C# is awesome).

Probably a bit of a rare problem I hit with this is that different NVENC generations generate different enough bitstreams that they can't be concatenated together. From my pool of machines I found out only my RTX 2070 and RTX 3080 Mobile are compatible. GTX 970 and Quadro P5000 that I had laying around both were incompatible with that pool and with each other.

Interestingly I found no similar software to the chunked encoding in my system, but am chalking it up on me not searching hard enough or these being integrated deep in to commercial/private systems. It would make sense that big players like YouTube have something like this in place, as reducing latency for individual upload transcodes finishing is beneficial instead of limiting their speed to a single hardware encoding / software encoding node. It's the same amount of processing that needs to be done in the end anyway, so might as well use 10 nodes to complete single jobs really quickly one after another

jauntywundrkind · a year ago
Not to steal thunder (nice! Well done!) but also this reminded me to go check in on https://kyber.media (currently a landing page), a ffmpeg streaming project from me ffmmpeg himself (I think?) Jean-Baptiste Kempf. He had a LinkedIn update two weeks ago, mentioning the effort! Yay! https://www.linkedin.com/posts/jbkempf_playruo-the-worlds-fi...

Submission from 6 months ago, https://news.ycombinator.com/item?id=39929602 https://www.youtube.com/watch?v=0RvosCplkCc

steelbrain · a year ago
Very cool! Thank you for sharing!
slt2021 · a year ago
this is really not much different from ssh-ing to your GPU server and running ffmpeg. Very roundabout way to execute remote bash command on a server

I dont meant to discourage you, but it is possible to replace your entire repo with a simple bash alias:

  alias ffmpeg-over-ip='ssh myserver "ffmpeg \"\$@\""'

steelbrain · a year ago
This comment gave me flashbacks to another comment I read a while ago: https://news.ycombinator.com/item?id=9224

If your usecase is solved by an alias, that's really good! I am glad you can use an alias. My usecase required a bit more so I wrote this utility and am sharing it with my peers

slt2021 · a year ago
Dropbox had a cutting edge file synchronization algorithm, they solved a problem of large file sync over unreliable network. There was a clear engineering IP they developed. (https://dropbox.tech/infrastructure/rewriting-the-heart-of-o...)

I looked over your source code and just saw a bash wrapper with webserver, so no significant IP. Any potential innovations: like possible distributed transcoding, sharding/partitioning transcoding pipeline to speed-up are missing.

its just a bash wrapper, thats why I commented about bash alias.

I don't mean to sound like a jerk, but I was honestly looking for some innovation about ffmpeg

KolmogorovComp · a year ago
> My usecase required a bit more so I wrote this utility and am sharing it with my peers

Can you expand on that?

asveikau · a year ago
I would add screen or tmux to that because you may run a long job that you may want to get back to after a connection drop.
amelius · a year ago
I suppose this only works if you have some shared filesystem. Or does this work with piping too?
slt2021 · a year ago
the original poster's project also requires shared filesystem.

as for bash-ssh solution, you don't need shared FS, if you don't need intermediate results. you can use SCP to get the final result after transcoding has finished. something like:

  alias ffmpeg-over-ip='ssh myserver "ffmpeg \"\$@\" /tmp/output/"'
  alias download-results='scp myserver:/tmp/output/*.* .'

  ffmpeg-over-ip <args> && download-results


my meta point being is, before engineering something with programming language, and handrolling webservers, with auth, and workers - just try to implement your system with bash scripts.

Martin Klepmann created an entire database using just bash aliases in his book "Designing Data Intensive Applications"

steelbrain · a year ago
The latest release[1] on Github should have binaries combinations for almost everybody here. If you don't find a binary for your environment, you can probably just run the javascript files and it'll be fine.

If you are wondering why the binaries are so large, it's because they are packaged-up node.js binaries. I tried to learn a compile-to-native language to rewrite this in so you won't have to download such bloated binaries but didn't get far. I learned Swift and still have a WIP branch up for it[2]. I gave up after learning that there's no well maintained windows http server for swift.

I'm currently on my journey to learn Rust. So maybe one day when I do, you'll see the binary sizes drop.

[1]:https://github.com/steelbrain/ffmpeg-over-ip/releases/tag/v3... [2]:https://github.com/steelbrain/ffmpeg-over-ip/tree/swift-lang

Cyph0n · a year ago
Go would be a good fit for this kind of application. But Rust is a great choice too.

Keep up the good work!

chrisldgk · a year ago
You might be able to switch to Bun or Deno with relatively little effort and create binaries that are probably a lot smaller (and maybe also faster) with each of their compile commands [1][2]. In the end I do also believe that a compiled language like Swift, Rust or Go might be a better fit though.

[1] https://docs.deno.com/runtime/reference/cli/compiler/ [2] https://bun.sh/docs/bundler/executables

steelbrain · a year ago
FWIW, `bun` produced larger output files

    ~/P/s/ffmpeg-over-ip  bun build ./src/client.ts --compile --minify --sourcemap --bytecode --outfile ffmpeg-over-ip-client ; ls -lah | grep ffmpeg-over-ip-client
      [6ms]  minify  -90.92 KB (estimate)
      [3ms]  bundle  6 modules
      [44ms] compile  ffmpeg-over-ip-client
    -rwxrwxrwx    1 steelbrain  staff    56M Oct  6 16:53 ffmpeg-over-ip-client

and `deno` produced even bigger outputs

    ~/P/s/ffmpeg-over-ip  deno compile --allow-read --allow-net ./lib/client.js ; ls -lah | grep client
    Compile file:///Users/steelbrain/Projects/steelbrain/ffmpeg-over-ip/lib/client.js to client
    -rwxr-xr-x    1 steelbrain  staff    65M Oct  6 16:56 client

VWWHFSfQ · a year ago
I used to use dvd::rip [1] (written in perl) that was sort of a similar concept. Deploy transcode jobs onto a cluster of servers accessing a shared filesystem (nfs, smb, etc.). worked really well. I think it used gstreamer though. I set up a homelab of a bunch of pentium 3s that I salvaged from a PC recycler behind my work. They just had a big pile of obsolete computers covered by a tarp. I grabbed a few chassis with working motherboards, and then scrounged around for the best intel CPUs I could find. and memory sticks. I put together a fun little DVD-ripping factory with those machines.

[1] https://www.exit1.org/dvdrip/