Settings

Theme

Offloading FFmpeg with Cloudflare

kentcdodds.com

46 points by heftykoo a month ago · 22 comments

Reader

bastawhiz a month ago

This was kind of a wild read. It starts with

> When I started building the Call Kent feature, I could have designed a proper job queue with a dedicated worker pool. But that would have been solving a scalability problem I did not yet have. "Start simple and iterate when reality tells you to" is still how I think about this. Reality finally told me.

And then we find ourselves at

> The signature uses HMAC-SHA256 with a shared secret, verified with a timing-safe comparison to avoid leaking information through response time.

Yikes, the complexity!

It took me thirty seconds to find the fly.io guidance to use BullMQ with Node+Redis.

https://fly.io/docs/blueprints/work-queues/

The recommendation is three lines of code. Instead, we have a queue, a queue worker, and an ffmpeg container running on two different vendors with two new internal API calls between services.

But also, this could all have been done in the browser. I did this ten years ago! https://pinecoder.pinecast.com

Start simple is fine, but this solution really seems like it overshot.

  • miyuru 25 days ago

    I was confused too.

    If I read the blog post correctly, this was to get a MP3 output from other audio sources. No video.

    He could created a few bash files and run in locally, assuming he is in the USA save ton of money spent creating the messy situation.

Doohickey-d a month ago

You can do this all in fly.io, no cloudflare container needed.

The whole selling point of fly is lightweight and fast VMs that can be "off" when not needed and start on-request. For this, I would:

Set up a "peformance" instance, with auto start on, and auto-restart-on-exit _off_, which runs a simple web service which accepts an incoming request, does the processing and upload, and then exits. All you need is the fly config, dockerfile, and service code (e.g. python). A simple api app like that which only serves to ffmpeg-process something, can start very fast (ms). Something which needs to load e.g. a bigger model such as whisper can also still work, but will be a bit slower. fly takes care of automatically starting stopped instances on an incoming request, for you.

(In my use case: app where people upload audio, to have it transcribed with whisper. I would send a ping from the frontend to the "whisper" service even before the file finished uploading, saying "hey wake up, there's audio coming soon", and it was started by the time the audio was actually available. Worked great.)

  • x0x0 a month ago

    It may be even easier to not even leave a vm in off. Using either the fly command or their api, you can kick off a one-off machine that runs an arbitrary script on boot and dies when that script ends.

    yanked from my script:

        cmd = [
          "fly", "machine", "run", latest_image,
          "--app", APP_NAME,
          "--region", options[:region],
          '--vm-size', 'performance-1x',
          '--memory', options[:memory] || '2048m',
          "--entrypoint", "/rails/bin/docker-entrypoint bundle exec rake #{rake_task}",
          "--rm"
        ]
        
        system(cmd)
    
    or a 1-1 transliteration to their api. You can of course run many of these at once.
  • michaelbuckbee a month ago

    That's a good trick (the "get ready" ping). It reminds me of how early Instagram was considered fast because they did the photo upload in the background while you were typing your caption so that by the time you hit "upload" it was already there and appeared instantly.

Havoc a month ago

As a side note, learned today that I've been running basically zero hardware acceleration for video on linux despite having a respectable GPU. It's all been CPU and I didn't realize.

nvidia-smi dmon

is the linux command (for nvidia) - column "dec" tells you whether there is hw decode happening. This will work both for browser (youtube) and video player (mpv etc). I needed to make active changes on both to get it to actually hit the gpu. Don't assume you've got hw accel just because it is smooth

  • temp0826 25 days ago

    Some linux distros (e.g. fedora) don't include hw decoding for licensing reasons. I decided I wanted all the latest goodies at some point and ended up duct taping together a copr repo with mesa/ffmpeg/mpv (latest from git) with all the hw stuff enabled (though I'm probably breaking some of their rules by doing so...I've labeled it in such a way that I hope nobody comes across it and decides to use it). Anyways, my main goal with it all was to extend battery life on my laptop while watching things, it makes a pretty big difference to use proper codecs.

meerab a month ago

We run a similar setup in production at VideoToBe – FFmpeg inside Cloudflare Containers with R2 mounted as a local filesystem via FUSE (tigrisfs).

On the debate about Cloudflare vs Fly vs spot instances – for bursty, infrequent workloads that already use R2 for storage, Containers are a natural fit.

The container accesses R2 over Cloudflare's internal network, so files never hit the public internet.

Check out our implementation - https://videotobe.com/blog/how-we-process-video-with-cloudfl...

(The main difference is we don't use Cloudflare Queues in conjunction with Cloudflare Containers. You can set max_instances to your desired settings to process parallel requests.)

thadk a month ago

Ffmpeg.WASM is really good and might manage all these steps before even uploading.

  • leptons a month ago

    This is what I've been doing, it works great. I've tested up to 4GB video files transcoded in the browser, then uploading the resulting video data. Also extracts thumbnail images, then uploads them to the server. Then I just do a quick verification server-side to check that it is actually a video or jpeg file, but the user's computer does all the work, so there is essentially zero cost for the whole ffmpeg transcode operation. It's brilliant.

PunchyHamster a month ago

Not sure why this isn't just run in local container, it's a podcast episode, not 4k video with heavy codec

  • input_sh a month ago

    At $31/month, I'm pretty sure that even with today's prices you could buy a dedicated machine for this purpose alone and that you would be saving $30 every month in like a year.

wewewedxfgdf a month ago

There's many many ways to solve this of course. Another possible solution might have been something that looks a bit like this:

Leave it on his primary server and use cpulimit to constrain CPU usage of ffmpeg to, say, 30% - this addresses the throttling problem:

cpulimit -l 30 -- ffmpeg -i input.mp4 -c:v libx264 -preset veryfast output.mp4

Then use the simplest of queueing mechanisms which is just to move files between directories - a long proven and reliable way to do a processing queue:

bash code here:

    #!/usr/bin/env bash
    set -u
    INCOMING="./incoming"
    PROCESSING="./processing"
    DONE="./done"
    FAILED="./failed"
    CPU_LIMIT=30
    SLEEP_SECONDS=2
    mkdir -p "$INCOMING" "$PROCESSING" "$DONE" "$FAILED"
    # recover files left in processing after a crash
    for path in "$PROCESSING"/*; do
        [ -e "$path" ] || continue
        name="$(basename "$path")"
        mv "$path" "$INCOMING/$name"
    done
    while true; do
        FILE=""
        # find first file in incoming
        for path in "$INCOMING"/*; do
            [ -f "$path" ] || continue
            FILE="$path"
            break
        done
        # if nothing available wait
        if [ -z "$FILE" ]; then
            sleep "$SLEEP_SECONDS"
            continue
        fi
        BASENAME="$(basename "$FILE")"
        STEM="${BASENAME%.*}"
        WORK="$PROCESSING/$BASENAME"
        OUTPUT="$DONE/$STEM.mp4"
        # move file into processing
        mv "$FILE" "$WORK"
        echo "Processing $WORK"
        # run ffmpeg under cpu limit (blocking)
        cpulimit -l "$CPU_LIMIT" -- ffmpeg -y -threads 1 -i "$WORK" -c:v libx264 -preset veryfast -c:a aac "$OUTPUT"
        STATUS=$?
        if [ "$STATUS" -eq 0 ]; then
            rm "$WORK"
            echo "Finished $OUTPUT"
        else
            mv "$WORK" "$FAILED/$BASENAME"
            echo "Failed $FAILED/$BASENAME"
        fi
    done
detuks a month ago

I would not suggest using cloudflare containers for ffmpeg. Feels like it is the nost expensive product they have. Queue to aws spot instances or just have dedicated hetzner machine

  • rozenmd a month ago

    This is the perfect use of cloudflare containers. Rare, bursty workloads that fit around regular use of Workers.

    I use them to generate thumbnails when uploading large photo files for my personal flickr clone, not even noticeable in billing.

  • pocksuppet a month ago

    This person is only running it for a few minutes once a week or so. Any pay-by-the-minute VM is fine for them.

DanielHB a month ago

Not really related to the topic, but I recently set up a baby-cam with ffmpeg by just telling ffmpeg to stream to the broadcast address on my home network and I can now open the stream from VLC on any device in the household.

A very heavy-handed solution, but super simple. A single one-liner. Just thought to share a weird trick I found.

  • pocksuppet a month ago

    It could be a little more efficient to use a multicast address. Even if you don't have any special multicast routing set up, all the receiving machines should be able to discard the traffic a bit earlier in the pipeline.

    • DanielHB 25 days ago

      yeah I tried that for a bit but didn't manage to get multicasting to work. My internal network is fine even with the extra broadcast traffic. This is not a permanent installation, eventually I won't need the babycam anymore.

      I saw some other solutions using nginx to serve the stream but that was much more complicated, just broadcasting is an one-liner (in a systemd daemon).

qmr 25 days ago

This seems overly complex, for what gain?

Any $5 VPS could do this number crunching, no?

flufluflufluffy 25 days ago

And here I am thinking if I needed to do that myself I’d just run it on my local machine and upload the final video to wherever it needs to go.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection