Skip to content

Instantly share code, notes, and snippets.

@transkatgirl
Last active October 29, 2022 11:33
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save transkatgirl/19363e3ef458ea206aec141ad9d8b382 to your computer and use it in GitHub Desktop.
Save transkatgirl/19363e3ef458ea206aec141ad9d8b382 to your computer and use it in GitHub Desktop.
Encode a video for uploading to Twitter using FFMPEG and FDKAAC
#!/bin/bash
# https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/uploading-media/media-best-practices
# - h.264 high profile
# - 60fps or less
# - aac-lc, he-aac not supported
# - 16:9 recommended
# - 512mb maximum
# - shorter than 140s
# - 1:1 pixel aspect ratio
# - yuv 4:2:0
# - up to stereo audio
# - no open gop
# - progressive scan
# - minimum recommended audio bitrate 128kbit/s
# https://help.twitter.com/en/using-twitter/twitter-videos
# - max resoultion 1920x1200
# - between 1:2.39 and 2.39:1
# - max video bitrate 25mbit/s
# https://help.twitter.com/en/using-twitter/how-to-use-live-producer
# - keyframe interval of fps*3
# a lot of these pages offered conflicting info (and sometimes outright wrong info too, like stating the max fps was 40 even though all the others stated 60), here's my attempt at trying to make sense of it all
# note that this script *may not* work with tweetdeck, it's only tested with the twitter web app
ffmpeg -i "$1" -vn -ac 2 -sample_fmt s16 "/tmp/audio.wav"
fdkaac -b 320k "/tmp/audio.wav" -o "/tmp/audio.m4a"
rm "/tmp/audio.wav"
vfilter="fps=fps=60,scale=-2:1080:flags=lanczos:out_color_matrix=bt709,setsar=1,format=yuv420p"
ffmpeg -i "$1" -i "/tmp/audio.m4a" -map 0:v:0 -map 1:a:0 -max_muxing_queue_size 1024 -t 2:19 -map_metadata -1 -vcodec libx264 -g 180 -keyint_min 180 -vf "$vfilter" -color_primaries bt709 -color_trc bt709 -b:v 25000k -bufsize 75M -acodec copy -movflags +faststart -map_metadata -1 output.mp4
rm "/tmp/audio.m4a"
#!/bin/bash
# same as encodetwitter.sh, but for encoding videos without audio
vfilter="fps=fps=60,scale=-2:1080:flags=lanczos:out_color_matrix=bt709,setsar=1,format=yuv420p"
ffmpeg -i "$1" -an -max_muxing_queue_size 1024 -t 2:19 -map_metadata -1 -vcodec libx264 -g 180 -keyint_min 180 -vf "$vfilter" -color_primaries bt709 -color_trc bt709 -b:v 25000k -bufsize 75M -movflags +faststart -map_metadata -1 output.mp4
@transkatgirl
Copy link
Author

transkatgirl commented Mar 12, 2021

My observations after working on this:

  • Twitter serves much higher quality video if you're playing it in full-screen (you can simulate this by watching a twitter video through youtube-dl).
  • Twitter will re-encode the video stream no matter what you do, yet is still extremely picky on what it will accept (which this script takes into account, and really spoon-feeds the encoder exactly what it wants, while trying to get the video quality as high as possible).
  • Twitter won't re-encode the (fullscreen) audio if you encode it correctly.
  • FFMPEG's AAC encoder is gives you horrid quality, yet FFMPEG devs will never accept the fact that their encoder sucks. libfdk_aac gives much better quality.
  • It's painfully hard to get a FFMPEG build with libfdk_aac built-in, so I decided to call it externally instead.
  • FFMPEG's RGB -> YUV conversion defaults to bt.604 by default, which makes no sense. The script tells FFMPEG to use bt.709 instead, which is a much more sane default.
  • Twitter's video documentation is very inconsistent and every page I could find offers conflicting guidelines.

So, in summary. Twitter video sucks and FFMPEG sucks. I'm going to take a nap, and when I wake up, I'll pretend I didn't waste three hours on this.

@transkatgirl
Copy link
Author

transkatgirl commented Mar 18, 2021

Decided to briefly revisit this, and here's what I've learned now:

  • It looks like the audio gets re-encoded too, no matter what. However, unlike Twitter's video encoder, their audio encoder thankfully doesn't suck (I didn't initially notice the re-encode when I was doing subjective comparisons, I had to manually analyze the audio to notice this).
  • Twitter actually supports >128kbit/s audio uploads, but Tweetdeck doesn't (as of the time of writing, this may change in the future). However, the maximum bitrate they support isn't stated anywhere, so I went with 320kbit/s (max recommended bitrate for fdkaac 44.1khz audio). Further bitrate increases will offer diminishing returns.
  • Twitter may support video bitrates >25mbit/s, but further bitrate increases will offer diminishing returns, and we're already getting close to the filesize limit.

So, it looks like we're very close to the limit of what Twitter will accept in a video upload, and further trying to push the limit really isn't worth the effort. We've got the best quality we're likely going to get.

why is twitter so picky when the whole thing is going to get re-encoded anyways
i hate this

@roblogic
Copy link

roblogic commented Mar 3, 2022

Very cool, thanks. Not sure why it adjusted the aspect ratio but it's not bad. I used the faac tool from homebrew instead of fdk-aac. It worked with the same inputs given in your script.

https://twitter.com/roblogic_/status/1499410750669934602?s=20&t=n2Sg7mKoik8sZfytT4EcTQ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment