Convert MPEG-TS, fMP4, and HLS streams to MP4 with clipping support - pure JavaScript, zero dependencies
npm install @invintusmedia/tomp4npm install @invintusmedia/tomp4
you've got an HLS stream, or some .ts segments, or fMP4 chunks.
you want an .mp4 file.
``js
import toMp4 from '@invintusmedia/tomp4'
const mp4 = await toMp4('https://example.com/stream.m3u8')
mp4.download('my-video.mp4')
`
that's it. no ffmpeg. no wasm. no dependencies.
`js
// HLS playlist (auto-picks highest quality)
const mp4 = await toMp4('https://example.com/master.m3u8')
// single .ts segment
const mp4 = await toMp4('https://example.com/segment.ts')
// raw bytes you already have
const mp4 = await toMp4(uint8Array)
// pick your quality
const hls = await toMp4.parseHls('https://example.com/master.m3u8')
console.log(hls.qualities) // ['1080p', '720p', '480p']
const mp4 = await toMp4(hls.select('720p'))
`
`js
// one-step: download HLS + clip (only fetches needed segments)
const mp4 = await toMp4('https://example.com/stream.m3u8', {
startTime: 0,
endTime: 30
})
// clip existing data (frame-accurate using edit lists)
const mp4 = await toMp4(data, {
startTime: 5,
endTime: 15
})
`
`js
// live stream saved as 4-second fMP4 chunks (each with init+data)
const segments = [segment1, segment2, segment3] // Uint8Array[]
const mp4 = toMp4.stitchFmp4(segments)
mp4.download('combined-stream.mp4')
// or with separate init segment
const mp4 = toMp4.stitchFmp4(dataSegments, { init: initSegment })
`
`js
// combine .ts segments into a single MP4
const segments = [segment1, segment2, segment3] // Uint8Array[]
const mp4 = toMp4.stitchTs(segments)
mp4.download('combined.mp4')
// or concatenate into a single continuous TS stream
const tsData = toMp4.concatTs(segments)
`
`js
const info = toMp4.analyze(tsData)
info.duration // 99.5 (seconds)
info.keyframes // [{index: 0, time: 0}, {index: 150, time: 5.0}, ...]
info.videoCodec // "H.264/AVC"
info.audioCodec // "AAC"
`
`js${info.percent}% - ${msg}
const mp4 = await toMp4(url, {
onProgress: (msg, info) => {
if (info?.percent !== undefined) {
console.log()`
}
}
})
// 10% - Downloading: 10%
// 50% - Downloaded 5.2 MB
// 60% - Frames: 300 video, 450 audio
// 100% - Complete
`js`
mp4.download('video.mp4') // trigger download
video.src = mp4.toURL() // play in video element
mp4.data // Uint8Array
mp4.toBlob() // Blob
mp4.toArrayBuffer() // ArrayBuffer
mp4.revokeURL() // free memory
remuxes video. no transcoding.
| input | output |
|-------|--------|
| .ts (MPEG-TS) | .mp4 |.m4s
| (fMP4) | .mp4 |.m3u8
| (HLS) | .mp4 |
video: H.264, H.265
audio: AAC
- transcode (no converting h264→h265, etc)
- handle DRM/encrypted streams
- support MP3, AC-3 audio (yet)
works in both. ~50kb minified.
`html``
MIT