Joining videos that were never meant to meet, without letting the sound drift
Joining two clips from the same camera is easy, because they already agree about everything. Real requests are rarely like that: a landscape screen recording followed by a portrait clip from a phone, one at 30 frames a second and the other at 60, one with sound and one without. A video file has one picture size, one frame rate and one soundtrack running the whole length, so every clip has to be brought into agreement before they can be joined. This page lets the first clip decide. The result takes its size and frame rate, and it says so before anything is encoded.
Pictures of a different shape are scaled down until they fit inside that frame and padded with black to fill it, never stretched, so a portrait clip inside a landscape frame keeps its proportions with bars at its sides. Every clip is then brought to the first clip’s frame rate, which repeats or drops frames as needed, so the joined file plays at one steady rate. Colour is converted to the format every player understands on the way.
Sound is where joins usually go wrong, and quietly. The joining step starts each clip where the longest part of the previous one ended. Recordings very often have sound that stops a fraction of a second before the picture, and if nothing is done about it, the next clip’s sound starts that much ahead of its picture, and the error adds up with every join. So before joining, each clip’s sound is padded with silence or trimmed to exactly the length of the clip, each picture is held on its last frame if it is the shorter one, and a clip with no sound at all is given the right length of silence. That was measured with three clips of different sizes and frame rates, the first with its sound 0.4 seconds short: the result was exactly 12 seconds of picture and 12 of sound, and a beep one second into the third clip landed exactly eight seconds after the beep one second into the first, where it belongs. Every frame is encoded again, so joining takes about as long as the clips play, and nothing leaves the browser tab.
The result is an MP4 with H.264 picture and AAC sound at 48 kHz in stereo, so a mono clip is spread across both channels and plays from both speakers, and clips recorded at different sample rates end up at one. Order matters for more than the sequence: moving a clip to the top changes the size of the whole result, which is why the output size shown on the page updates as clips are moved. Every clip is read into the tab’s memory together with the joined file being written, so a handful of phone clips joins comfortably, while several long recordings at once can exceed what a phone browser allows. When that happens the engine’s own message is shown rather than a blank failure.