Vanilagy / mp4-muxer

MP4 multiplexer in pure TypeScript with support for WebCodecs API, video & audio.
https://vanilagy.github.io/mp4-muxer/demo
MIT License
419 stars 32 forks source link

Works on Chrome but not on Safari #36

Closed AmitMY closed 7 months ago

AmitMY commented 8 months ago

Strangely, I can create valid mp4 videos in Chrome, but fail to do so in Safari. Safari does not complain about an unsupported codec or anything.

I create an mp4 muxer using the codecs in the example in the README

    const {Muxer, ArrayBufferTarget} = await import('mp4-muxer');

    // Set the metadata
    this.container = 'mp4';
    this.codec = 'avc1.42001f';
    // H264 only supports even sized frames
    this.width = this.image.width + (this.image.width % 2);
    this.height = this.image.height + (this.image.height % 2);

    // Create the muxer
    this.muxer = new Muxer({
      target: new ArrayBufferTarget(),
      fastStart: 'in-memory',
      video: {
        codec: 'avc',
        width: this.width,
        height: this.height,
      },
    });

Followed by a VideoEncoder

    this.videoEncoder = new VideoEncoder({
      output: (chunk, meta) => this.muxer.addVideoChunk(chunk, meta),
      error: e => console.error(e),
    });
    const config = {
      codec: this.codec,
      width: this.width,
      height: this.height,
      bitrate: this.bitrate,
      framerate: this.fps,
    };
    this.videoEncoder.configure(config);

Full reproduction video:

https://github.com/Vanilagy/mp4-muxer/assets/5757359/dac0c7cc-67ed-4840-8630-e1682b3421f7

Vanilagy commented 8 months ago

Sorry for the late response, I've been busy. First of all, I really love these reproduction videos. Super easy to follow, and great to hear somebody's voice instead of just reading text! And I've almost memorized the ASL for "test" by now ^^

Now, I assume you've run the official mp4-muxer demo in Safari and Chrome, right? Did those work? Given that your Safari output mp4 file here is only 500 bytes, something seems terribly wrong. I wouldn't even expect the entire metadata/header block of the mp4 file to fit into that small a space, so there's a chance some application logic is wrong here. But that doesn't explain why it works just fine in Chrome. I don't really have any concrete ideas on how to approach this.

Could you perhaps record yourself showing how well the webm-muxer and mp4-muxer demos work on your machine, in both Chrome and Safari? I'll try them on my Mac in the meantime. How different are the code paths taken to encode VP9 vs AVC in your application? I assume they look somewhat analogous.

Vanilagy commented 8 months ago

Okay so, the mp4-muxer demo works perfectly on Safari on my Mac. Could you compare the demo code to your application and look for differences, maybe in the config, or in the way the encoder is called/its output received? Those 500 bytes of output size really confuse me, are you sure that's the actual size?

AmitMY commented 8 months ago

After much experimentation with your demo, I found it is a bitrate limitation. I use 1e9 to act as infinite, but in fact only 1e7 and below works in safari with your library. Is it possible to throw some error if the configured limit is too high? (this works in chrome though)

Vanilagy commented 8 months ago

Don't use a bitrate of 1e9 or of infinity! This is a field that's supposed to be intentionally set to tell the encoder how hard to compress. For the absolute best quality, I typically use 10 Mbits = 1e7, but given the simplicity if your output, this seems overkill. I'd try anything between 1e5 and 1e6, results should still be great. I would experiment going as low as possible until the quality becomes noticably bad.

AmitMY commented 8 months ago

My output can actually be more complex (like a generated human, which will work at some point).

But I guess now this is becoming an issue of - can we actually raise an error when the bitrate selected by the user is unsupported by the browser? (since this is supported in chrome, but not safari) Can we see this information in the addVideoChunk?

https://github.com/Vanilagy/mp4-muxer/assets/5757359/2083036c-ecba-4296-a453-f0aa21fa64f5

Vanilagy commented 8 months ago

I think this is a Safari internals bug; if Safari cannot support 1e9, it should error saying that the codec configuration is unsupported. But it silently fails. You could do crazy things like render a fake, 5-frame test video using the configured bit rate, and then seeing if it plays back or not. But my point is: Don't allow the user to select these crazy high bitrates! Anything beyond 1e7 is very overkill.

Vanilagy commented 7 months ago

I'll close this issue for now. If you still need help with anything, feel free to reopen it :)