How to stream a local video file to Twitch with ffmpeg.
It occurred to me one day that I have an occasional need (“need” is a strong word here) to show off a game video that I’ve recorded, but I don’t want to wait for it to be uploaded as part of my regular schedule of YouTube uploads. It can take months for a video I’ve recorded to show up on YouTube, especially if it’s part of a game series. For example, two nights ago, I played what might someday become “episode 7” of a Resident Evil 7 video series. But at this time I have no idea if I’ll ever finish the game or upload it.
I still have unfinished Morrowind and Oblivion seriesessses on my YouTube channel, which is a constant source of consternation, so I have resolved never to upload another game series until I’m finished playing the game. So a lot of game videos accumulate on my hard drive, waiting to be uploaded.
For example, as of this writing, I have the following game series videos in various states of completion: The Surge, Hellpoint, Resident Evil 7, Baldur’s Gate Enhanced Edition, Pillars of Eternity 2: Deadfire, and probably some others I can’t remember. I might record Greedfall and/or A Plague Tale, if I can figure out a good way to do it. Oh, I also have a complete playthrough of The Witcher, and a partially-completed The Witcher 2 series.
Anyway it’s a lot of videos sitting around waiting to upload someday. The idea is to make sure I have enough videos in a hopper to schedule an upload every day for the rest of time. It takes up a lot of space, but the topic of storing and backing up terabytes of video files is another topic.
The point is, sometimes I’d like to be able to publish one of the in-progress videos somewhere, and I can’t do it on YouTube. For example, Magi mentioned Hellpoint in his Humble Bundle post, and I just happen to have played it recently because I buy most Souls-like games at one point or another. I have a video sitting right here that can show exactly what Hellpoint looks like.
But I can’t upload a one-off video to YouTube today, and then upload the same video six months from now as part of a series. For one thing, YouTube does a scan and doesn’t let you upload the same video twice, and for another, it would wreck all kinds of stats. It’d be like publishing part 4 of a blog series before you finish the blog series or even post the first part, which is weird.
The obvious answer is Twitch. But Twitch is normally meant for live-streaming, something I’m not terribly interested in doing. Still, it’s a useful place to distribute/store videos, at least temporarily.
There was a brief time period when regular peons could simply upload a video file to a Twitch channel, without having to be a partner or affiliate or whatever they call it. Apparently you can’t do that anymore.
Fortunately, Twitch, to this day, is rather lax about access to their intake servers. So you can stream anything to your Twitch channel, as long as you know how to connect to an RTMP server. It doesn’t necessarily have to be recorded live with OBS or Streamlabs or whatever. It could just be a video file sitting on your hard drive.
So I setup an ffmpeg script that takes a video file as an input and streams it to Twitch. Here is an annotated version of the command I use:
ffmpeg \ -re \ -i "yourvideofile" \ -c:v libx264 \ -preset veryfast \ -b:v 6000k \ -bufsize 6000k -minrate 6000k -maxrate 6000k \ -bf 2 \ -pix_fmt yuv420p \ -g 120 -keyint_min 120 \ -c:a aac \ -b:a 128k \ -map 0:0 \ -map 0:1 \ -f flv rtmp://live.twitch.tv/app/yourstreamkey
- -re Stream the video at playback rate, instead of as fast as possible.
- -i “yourvideofile” This is the video file you want to stream to Twitch. It can be basically any video format ffmpeg can read. I use either mp4 or mkv. It needs to have at least one video channel and one audio channel. (Well, I guess you could stream a video with no audio channel if you really wanted to.)
- -c:v libx264 Use the H264 codec for video encoding.
- -preset veryfast This determines how fast the encoding will occur. I picked veryfast, which isn’t quite the fastest, but pretty fast, at the cost of quality. You can tweak this depending on how much you care about quality and how much your CPU can handle. You have to be able to encode frames at least as fast or faster than the frame rate of your video.
- -pix_fmt yuv420p I feel like YUV420p is the default for video, but this ensures it’s consistent for whatever reason. I don’t remember why I specified it explicitly but it might have been a Twitch recommendation.
- -b:v 6000k Encode the video at 6000kbps. This is your main parameter to determine video quality. Twitch defaults to around 3000kbps I think which is just awful so I made it a little better. As far as I can tell, Twitch does not re-encode your video like YouTube does, and just stores it as-is, so this is probably also the Internet bandwidth requirement that viewers will need to see your video.
- -bufsize -minrate -maxrate Encoding is normally a variable-bitrate kind of thing in ffmpeg, these parameters force it to a more constant bitrate that is better for streaming. It should be set to the same as what was used in -b:v.
- -bf 2 I think this sets “B-Frames” to 2, but I don’t remember what that actually does. I think it’s a Twitch recommendation. Weirdly I can’t find any ffmpeg documentation on this parameter so it might not do anything.
- -g 120 -keyint_min 120 Specifies the keyframe interval, in frames. So if your video is 60fps, a keyframe interval of 120 means every 2 seconds, which I think is what Twitch recommends. If you don’t specify, ffmpeg will just do whatever it thinks is best, which is very inconsistent.
- -c:a aac Use the AAC codec for audio encoding, which is the norm for MP4 videos.
- -b:a 128k Set the audio encoding bitrate at 128k, which is a modest audio quality. Some people use higher bitrates for streamed game audio but I personally think it’s a waste of bandwidth.
- -map 0:0 Output the first stream in your source file first, which should be the video stream.
- -map 0:1 Output the second stream in your source file next, which should be the audio stream. (In my case, the first audio stream is the mix of game sound and my commentary. I sometimes use -map 0:2 here if I just want to output the second audio channel, which is just the game sound by itself.)
- -f flv rtmp://live.twitch.tv/app/yourstreamkey Lastly this specifies where to stream the file, which is a Twitch RTMP intake server. Replace “yourstreamkey” with your stream key, obviously. You’ll get it from a Twitch dashboard page somewhere that I can’t remember off the top of my head. If you don’t know how to find your stream key, you probably shouldn’t be trying to run ffmpeg in the first place. There may be some port security and firewall stuff involved in successfully streaming to an RTMP server, but my PC “just works.” Presumably if you can stream to Twitch the normal way, you can also run this ffmpeg command.
I developed the above settings when I was working on setting up my own Linux RTMP server to stream to multiple services at the same time (YouTube, Twitch, and Mixer, at the time). During that time, I made use of something called the Twitch Stream Inspector, which examines the bits and bytes of your streams. Some of those settings may have come from that tool’s recommendations.
Incidentally it’s baffling to me that Twitch doesn’t appear to do any authorization on that intake server. Guess somebody’s stream key and you can start streaming videos to their channel no questions asked. Feels like a pretty big security hole they would want to fix.
Anyway if you want to see what Hellpoint gameplay looks like, you can watch it here (there’s no built-in Hugo shortcode for Twitch unfortunately), at least until Twitch deletes it I think 14 days from now. It was streamed with a command similar to the above.
Another one I streamed in this way was an annoying boss fight in The Surge. I spent a bunch of time editing that video but I don’t know if I’ll ever actually finish The Surge and upload a YouTube series. You might have to hurry to watch that one, as it’s pretty close to expiring.
It’s pretty cool. Streaming without any of the hassle of streaming. :)