Convert MPEG-TS and fMP4 streams to standard MP4
npm install @invintusmedia/tomp4
.ts, .m4s, or .m3u8 + segments
import toMp4 from '@invintusmedia/tomp4'
// Convert from URL
const mp4 = await toMp4('https://example.com/video.ts')
mp4.download('video.mp4')
// Convert from raw bytes
const mp4 = await toMp4(uint8Array)
// Play in video element
video.src = mp4.toURL()
// HLS stream (auto-selects highest quality)
const mp4 = await toMp4('https://example.com/stream.m3u8')
// Pick specific 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'))
// Limit segments (for previews)
const mp4 = await toMp4(url, { maxSegments: 5 })
// 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 (snaps to keyframes)
const mp4 = await toMp4(data, {
startTime: 5,
endTime: 15
})
const mp4 = await toMp4(url, {
onProgress: (msg, info) => {
if (info?.percent !== undefined) {
console.log(`${info.percent}%`, msg)
updateProgressBar(info.percent)
}
}
})
// 10% Downloading: 10%
// 50% Downloaded 5.2 MB
// 60% Frames: 300 video, 450 audio
// 100% Complete
// Analyze without converting
const info = toMp4.analyze(tsData)
info.duration // 99.5 (seconds)
info.videoFrames // 2985
info.audioFrames // 4307
info.keyframes // [{index: 0, time: 0}, ...]
info.videoCodec // "H.264/AVC"
info.audioCodec // "AAC"
// Mp4Result methods
mp4.download('video.mp4') // trigger download
mp4.toURL() // object URL for video.src
mp4.toBlob() // Blob
mp4.toArrayBuffer() // ArrayBuffer
mp4.data // Uint8Array
mp4.size // bytes
mp4.sizeFormatted // "2.5 MB"
mp4.revokeURL() // free memory