(Last updated: December 17, 2019)


(It's well-known that the denizens of Eden-6 enjoy Space Janitors)

Most of the game data for Borderlands 3 is stored inside encrypted .pak files which takes some effort to extract, and isn't easily editable. However, one exception is a collection of video files which live in the directory OakGame/Content/Movies. These files are used in a variety of places throughout the game:

I am far from the first person to think about replacing those -- in fact, it had never even occurred to me until I heard someone else talking about how they'd replaced the opening logo vids on their own PC. Still, I was intrigued by the possibilities! There's two things in particular I wasn't super fond of with BL3:

  1. Live-Action Siren-mind Communication: This has always bugged me, and felt even more out of place in BL3 for some reason.
  2. CoV Propagand Vids: By the end of my first runthrough, I was kind of tired of hearing those two main "liarhawk" and "done and dusted" videos -- the music and the repetetive sound effects would just set me on edge. Which was clearly the point, but I was tired of hearing 'em.

So, I went ahead and replaced 'em, and figured I may as well document it for anyone else who may be interested.

General Video Processing

I've processed the videos using the video processing tool FFmpeg, which has long been a staple of video processing, at least on Linux (it's also available for Windows). I run Borderlands 3 on Linux, via Wine/Proton (specifically via a WINEPREFIX supplied by Lutris). The scripts and things here assume you're on Linux, though as I say, FFmpeg should work fine on Windows. You'd have to be out on the command line to use it. Additionally, the actual scripting bits I used are in Python 3.

I've only done this for the Siren-communication and CoV propaganda vids, so I can't say for certain that the other videos are the same. The conversions that I did will force the input video into the aspect ratio used by the stock in-game videos, so if you're using a source video that's not 16:9, it'll end up getting stretched oddly. Personally I was happy with that, given the silliness of the whole endeavor, but there are examples online of having FFmpeg add in black-bar banding where appropriate. You'll have to do your own research for that.

I used a two-step encoding process while making these, which is what FFmpeg recommends, though I suspect a single-pass encoding would probably be good enough for this application, especially given the CoV propaganda video sizes. Regardless, the two general FFmpeg commands that you'd want to run in order to get the videos as close as possible to the original formats is this:

/usr/bin/ffmpeg \
    -y \
    -i /path/to/input_file.mp4 \
    -filter:v scale=w=WIDTH:h=HEIGHT:force_original_aspect_ratio=disable,fps=fps=FPS \
    -aspect 16:9 \
    -c:v libx265 -b:v 2800k \
    -profile:v main \
    -an \
    -pass 1 \
    -f mp4 \
    /dev/null

/usr/bin/ffmpeg \
    -y \
    -i /path/to/input_file.mp4 \
    -filter:v scale=w=WIDTH:h=HEIGHT:force_original_aspect_ratio=disable,fps=fps=FPS \
    -aspect 16:9 \
    -c:v libx265 -b:v 2800k \
    -profile:v main \
    -c:a aac -b:a 189k \
    -ar 48000 \
    -pass 2 \
    -metadata:s:a:0 language=eng \
    -metadata:s:v:0 language=eng \
    /path/to/output_file.mp4

Replace WIDTH, HEIGHT, and FPS as appropriate (and also any of the other parameters, though those are what all the videos I looked at used). A single-pass encode probably looks like:

/usr/bin/ffmpeg \
    -y \
    -i /path/to/input_file.mp4 \
    -filter:v scale=w=WIDTH:h=HEIGHT:force_original_aspect_ratio=disable,fps=fps=FPS \
    -aspect 16:9 \
    -c:v libx265 -b:v 2800k \
    -profile:v main \
    -c:a aac -b:a 189k \
    -ar 48000 \
    -metadata:s:a:0 language=eng \
    -metadata:s:v:0 language=eng \
    /path/to/output_file.mp4

One thing to note is that it looks like the videos can basically be any length, at least for the CoV propaganda vids. I'd personally kept my replacements to the same length as the original videos, but that's probably not a requirement. I did not test that with the Siren communication videos, though. Note that the output videos are not exactly like the stock BL3 versions -- for instance, the stock videos specify their colorspace information more fully than these ffmpeg-produced ones do. The ones I produced worked just fine, so I didn't bother tracking it down.

Keep in mind that whenever there's a patch to BL3, EGS (or Steam, presumably, once it arrives on that platform) will overwrite any altered videos with the default versions. So keep that in mind!

Children of the Vault Propaganda Videos

The CoV propaganda videos are all in a super-low resolution of 320x180, at 30 FPS. The stock videos use a video bitrate of about 2800k for all of them, which is absurdly high for that resolution. In my own testing, I didn't notice any quality drop even going down as low as 90k. I did start noticing artifacts around 50k, so I wouldn't recommend going that low. So feel free to alter that -b:v parameter to suit, if you want, though if you keep the video lengths the same as the original vids, it hardly matters. You can probably drop the audio bitrate down to 128k without noticing any difference, too, if you like (or even 96k, but I didn't try that myself).

Personally, I'd wanted to have the videos be randomized inbetween my runs of BL3, so I get a fresh surprise whenever I come across them. So, I wrote a Python script to do that for me. It's got an input_dir defined near the top which is expected to have other subdirectories in it, and it'll first choose a random directory, and then pull a random video file from that directory. So for instance in my /usr/local/games/bl3-vids dir, I've got a directories for: Bee and Puppycat, Bravest Warriors, Invader Zim, the JAndrew TNG edits, Space Janitors, and The TIck (the 90s cartoon version). I just run it manually between runs, so kicking it off isn't really automated at all.

The script: bl3vid-randomize.py

The specific videos that I randomize are:

  • VidScreen_JoinTheCoV.mp4 (length: 22.61)
  • VidScreen_RecruitmentCheck.mp4 (length: 13.03)
  • VidScreen_TheGreatVault.mp4 (length: 32.04)
  • VidScreen_PhaseblockedShort.mp4 (length: 14.31)
  • VidScreen_PluckedShort.mp4 (length: 18.69)
  • VidScreen_SOTD_Buried.mp4 (length: 14.04)
  • VidScreen_SOTD_Dissolved.mp4 (length: 15.04)
  • VidScreen_SOTD_Pooped.mp4 (length: 17.71)
  • VidScreen_SOTD_Sawed.mp4 (length: 13.03)
  • VidScreen_SOTD_Squished.mp4 (length: 15.04)

Of those, only VidScreen_PhaseblockedShort.mp4 and VidScreen_PluckedShort.mp4 are likely to be encountered more than once in a playthrough, but I went ahead and did all of 'em anyway.

The script uses ffprobe (part of the FFmpeg package) to query info about the source vids, to find out how long they are, so we can pick a random start time to choose from. It then pulls just enough video out of the source material to match the length of the original videos. It also does some relatively needless fade-in and fade-out filtering. The extra FFmpeg arguments (and an altered -filter:v argument) that end up being used are:

    -ss STARTTIME -t TARGETLENGTH \
    -filter:v scale=w=WIDTH:height=HEIGHT:force_original_aspect_ratio=disable,fps=fps=FPS,fade=t=in:d=0.5,fade=t=out:d=0.5:st=FADEOUTSTART \
    -filter:a afade=t=in:d=0.5,afade=t=out:d=0.5:st=FADEOUTSTART \

The -filter:a statement only needs to be run in Pass 2, if using a two-pass encode. I use a half-second fade-in/fade-out parameter. STARTTIME is the timestamp to start in the input video, TARGETLENGTH is the length of the video, and FADEOUTSTART is the point at which to start fading out (which should be TARGETLENGTH minus 0.5 seconds).

Kind of a stupid amount of work, but I've found it highly amusing when in-game, though stopping to watch a cartoon during a pitched battle is not a great survival strategy.

Siren Mind-Communication Videos

These videos are all named Lilith-*.mp4 and Tannis-*.mp4, and have a resolution of 960x540 at 29.97 FPS. They average about 2400k for the video bitrate, which is amusingly lower than the 320x180 videos used in CoV propaganda. These videos have no audio track, so they're video-only. They're also all just about exactly 10 seconds long (ffprobe reports 10.01, but that could just be rounding).

I actually didn't bother to script out anything here, since these have some stricter limitations as to what will look decent onscreen, and you'd probably need to zoom around a bit to have things centered reasonably. So I ended up just doing these by hand in a manual video editing app.

I also didn't bother making different videos for each expression (such as excited, happy, panicked, etc), since finding appropriate source videos for those would be kind of annoying. So instead, I just grabbed a video of a corgi for Lilith, and a greyhound for Tannis (neither are the best vids for this purpose, honestly -- the corgi video's quite bouncy, and the greyhound never really looks into the camera). Please don't read anything into that video selection other than that I like dogs a lot, and figured that if I'm going to have live-action video talking to me, I might as well be looking at a corgi while doing it. Note that the Tannis videos in particular only show a smallish bit of the video around the center -- you'll need to make sure that her videos are zoomed-out a bit more than Lilith's.

Anyway, the above bl3vid-randomize.py actually copies over some hardcoded video paths to replace these videos as well.

Borderlands 3 As a Media Player

Once I'd had all this in place for awhile, I got to wondering about the video-length question. My script had been replacing the videos with basically identically-long alternates, but what if I wanted something longer? Could I watch a whole Space Janitors episode in-game? How about a whole episode of The Tick? How about Die Hard? Well:


Well, hello there.

Hans Gruber's looking nice.

John McClane's not too happy about it, though.

As far as I can tell, BL3 will probably let you plug in basically any video in there, no matter how long. One major problem is that if you hit Escape to pause the game, the audio doesn't recover once you go back into the game (though the video will continue to play). So as a generic media player, Borderlands 3 lacks a certain je ne sais quoi. Also notably absent are any video control functions on the TVs. Sometimes it feels like Gearbox is hardly even trying, I mean, come on folks.

I stripped down my randomizer script above to do the video conversion here. I did drop the video quality down to a more-reasonable 90k, since otherwise my converted Die Hard video, at 320x180, was more than twice as big as the source file I was converting from (which was 720p). It clocks in at about 200MB, post-conversion, which BL3 seemed to handle just fine. I only watched about 35 minutes, but I didn't see any indication that it would stop at any point.

The script: bl3vid-single.py

That particular TV in the screenshots is in The Anvil, in the foyer area just after you've gone into the complex itself. It plays VidScreen_PhaseblockedShort.mp4. This is the only TV I know of that activates every time for sure, though I didn't look for more once I found this one. There's a handy New-U right there, too. I'm guessing there's at least a few other guaranteed-activation TVs strewn about, though.

Conclusion

Not much more to say here, really! One thing I haven't tested yet is what happens if BL3 encounters a video that's in different resolutions, aspect ratios, framerates, colorspaces, etc, than the stock videos. I suspect that they're probably just using builtin UE4 stuff to play videos, so my guess is that it would probably play just fine, but I'd figured the path of least resistance was doing some conversions.

As for other videos in that Movies directory, you can have BL3 skip Marcus's New Game introduction by removing MARCUS_INTRO.mp4 entirely, though as of a recent patch, that should be skippable in-game.

The 2K/Gearbox/AMD logo videos are probably easily replaceable, though removing them doesn't really save you any startup time -- the game seems to be loading data in the background while they play, and without having done actual timing, it seemed like you just get a longer Claptrap-dance loop without them, so I've not really bothered with them.

Relatedly, the Claptrap-dance video should be replaceable as well; I heard someone say that it should remain the same length as the original, but I wonder if it'll loop properly regardless of length.

Other than that, there's some other VidScreen*.mp4 videos that I didn't touch, such as the communications you get from Troy and Tyreen throughout the game, and a mysteriously-1080p video from Mouthpiece, which is the highest-resolution video in the dir. Most of those which involve dialogue don't actually have the dialogue in the audio track directly; that's localized elsewhere, and the engine layers the appropriate language audio track over the top. The videos VidScreen_Phaseblocked.mp4 and VidScreen_Plucked.mp4 are the "long" versions, including Troy+Tyreen sequences, of VidScreen_PhaseblockedShort.mp4 and VidScreen_PluckedShort.mp4. Theoretically it wouldn't be too hard to stitch together edited versions of those which leave Troy+Tyreen (so their dialogue continues to work) but replace the interior videos as we do with the short versions, but that hardly seems worth the effort.

Annnd that's about it! Enjoy, if this is your kind of thing. :)

Changelog

December 17, 2019
  • Initial post