toMp4.js

Convert MPEG-TS and fMP4 streams to standard MP4

Zero Dependencies Pure JavaScript Browser & Node.js
npm install @invintusmedia/tomp4

Drop files here

.ts, .m4s, or .m3u8 + segments

✓ Supported
H.264, H.265, AAC
✗ Not Supported
MPEG-1/2, MP3, AC-3
sec

Console

Ready to convert video files...

Usage

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