npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mp4-to-mcap

v0.2.0

Published

Convert an MP4 video file to an MCAP file by repackaging its H.264/H.265 bitstream into foxglove.CompressedVideo messages, re-encoding only when needed to strip B-frames that Foxglove's video panel can't play back.

Downloads

40

Readme

mp4-to-mcap

Convert an MP4 video file to an MCAP file. Each video frame is repackaged into a foxglove.CompressedVideo message, so the result plays back in Foxglove Studio or any other Foxglove-schema-aware MCAP viewer.

npx mp4-to-mcap input.mp4
Converting |████████████████████████████████████████| 100% | 300/300 frames | ETA: 0s
Wrote 300 h264 frames (1920x1080, 10.00s) to input.mcap (42.31 MB)

Why "no transcoding" (usually)

The video bitstream inside your MP4 is already H.264 or H.265 encoded. In the common case, this tool doesn't decode and re-encode it — it demuxes the MP4 container in pure JS (no ffmpeg, no protoc), converts each sample from MP4's length-prefixed NAL format to the Annex-B start-code format foxglove.CompressedVideo expects, and writes one message per frame. The encoded pixels never change.

On every keyframe, the track's SPS/PPS (and VPS, for H.265) parameter sets are prepended so the bitstream is self-decodable from that point — the same thing a camera-facing encoder does natively.

The one exception is B-frames — see below. When the source uses them, this tool falls back to a real transcode via a bundled ffmpeg binary before repackaging.

Install

npm install -g mp4-to-mcap

Or run it once with npx mp4-to-mcap ... without installing.

Usage

mp4-to-mcap <input.mp4> [options]

Options:
  -o, --output <path>   output .mcap file path (default: <input> with .mcap extension)
  -t, --topic <topic>   MCAP topic for the video channel (default: "/camera/h264")
  --frame-id <id>       frame_id recorded in each CompressedVideo message (default: "")
  -q, --quiet           suppress the progress bar
  -V, --version         output the version number
  -h, --help            display help

As a library

import { convertMp4ToMcap } from "mp4-to-mcap";

const result = await convertMp4ToMcap("input.mp4", "output.mcap", {
  topic: "/camera/h264",
  onProgress: (framesWritten, totalFrames) => {
    console.log(`${framesWritten}/${totalFrames}`);
  },
});

Limitations

  • Codecs: only H.264 (avc1/avc3) and H.265 (hvc1/hev1) video tracks are supported — the whole point of this tool is repackaging an existing bitstream, so other codecs (VP9, AV1, ...) aren't handled.
  • B-frames: Foxglove's video panel has no reorder buffer / lookahead, so it can't play back a stream where presentation order differs from decode order (a documented limitation of foxglove.CompressedVideo itself). When this tool detects B-frames (sample.cts !== sample.dts), it prints a warning and automatically re-encodes the video without them (ffmpeg -bf 0) using a bundled binary from ffmpeg-static before repackaging. Two things follow from that:
    • It's a real transcode, not a lossless remux: the frame is decoded and re-compressed, which costs a generation of quantization loss on top of whatever the source already lost, plus B-frames' own compression-efficiency advantage (they're typically the cheapest frame type to encode), so expect a modestly larger and/or slightly lower-fidelity output than the source. Frame count, frame rate, resolution, and colorspace are unaffected.
    • ffmpeg-static bundles a real per-platform ffmpeg binary, so installing this package downloads one (tens of MB) and is noticeably heavier than a pure-JS install. That binary (and the libx264/libx265 encoders it links) is GPL-licensed; this package's own MIT license covers only its own code.
  • Audio and other tracks in the source MP4 are ignored; only the first video track is converted.
  • The whole input file is read into memory.

The foxglove.CompressedVideo convention

This isn't a bespoke format — it's the same schema and per-frame-message structure that coScene's own MCAP video tooling (encoders that produce .mini.mcap files, OSS video extraction pipelines) already uses. If you're working in that ecosystem, output from this tool is drop-in compatible.

License

MIT