-
-
Notifications
You must be signed in to change notification settings - Fork 8.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Native Hybrid MP4 Muxer #10608
Native Hybrid MP4 Muxer #10608
Conversation
74b0de6
to
c40e5bf
Compare
Would it make sense to actually make this the new default MP4 muxer at some point (give that it kinda achieves a "best of both worlds") and offer it that way as a "beta" variant at first (and drop the "Hybrid" part that might just incur additional questions)? My only real concern is if we offer it (even flagged as "experimental" without multichannel and multi-track audio support (HDR metadata is "should-have" because of HEVC support) because fine print is very often not read and users might get burned by their recordings missing those things. Which would mean the scope should be:
|
That's my mid-term goal, at least for Windows/Linux, for macOS I'd want to add support for the MOV specifics necessary to support ProRes first.
HDR support should be relatively easy to add, I just didn't get around to it yet. Afaik it just requries writing two additional boxes of metadata (
Pretty much my plan. |
Tested the feature out, encountered some problems: The stats panel doesn't show anything for total data output/bitrate/'disk full in...'/etc while recording. Multitrack audio doesn't work, only the first track is recorded. I did a ~1h44m recording, however the duration is not showing in file explorer/it has the usual fMP4 inconveniences (+ visual playback is garbled whenever I seek in mpv or mpc-hc until I reach the next keyframe in the recording). Looked at the log and I can see that right when I stopped the recording, it says this: After this I experimented a bit, with some recordings it comes out completely fine, the hybrid container seems to work as expected. Others, however, will at random get the same error text in the log mid-recording (at which point nothing gets recorded anymore, and the resulting file will only play (with the same issues described in the previous paragraph) up to the point of the error). Example log here. I start recording, 30s later the error happens, ~46s later I stop recording, and there is only 30s of video to watch in the resulting file. Let me know if providing the raw recordings is of any use/help, feel to ping me on Discord (@/aciidz) if it's more convenient or something (I'd be much quicker to respond there than here, at the very least). Can also go for a minimal repro on a completely clean portable build with none of my plugins/scenes/etc if that's desired as well, though I can't imagine how what I currently have would be causing the bugs. |
Multi-track audio wasn't working because I forgot the The write error is very odd, I wonder if the error isn't being logged correctly, will have to see if I can reproduce. For now I changed the logging a bit and also made sure the output will stop with an error when the issue occurs. The other issue (garbled video until you get to a keyframe) sounds like perhaps some file offsets aren't being calculated correctly, will have to investigate. Finally, output bitrate/bytes written stats were not visible because I forgot to add Edit: Forgot to mention I also added support for the HDR metadata boxes so now that should work fine as well. In diving into channel layouts I discovered that FFmpeg doesn't bother writing those for non-PCM codecs, presumably because they're self-describing. But that will require a bit more research. |
84aeac3
to
2739f0f
Compare
Okay I found what's causing this, the large size (>4 GiB) field wasn't written correctly. If you open the file in a hex editor and search for the first This is now also fixed. Edit: Seems there might still be an issue with fragmentation not always happening on keyframes, will continue to investigate. |
adfa7c2
to
d976d99
Compare
Okay the keyframe issue should be fixed as well now, it was the result of the sample flags in fragments not being correct due to a little endiannes mistake. A soft-remuxed file should not be affected as keyframe indices in the full |
There's a typo in the Tried the latest build, worked fine with a handful of very short recordings, but I have a new problem. Did a ~18.5 minute recording where the duration isn't showing in file explorer, but it opens quickly (like a normal mp4) in mpc-hc/mpv/mediainfo/etc. However when I tried to start another recording, nothing happened (aside from the Start Recording button getting highlighted until I clicked it again), trying to exit OBS just results in an indefinite hang. Link to the log where this happened (note that I successfully did a bunch of shorter recordings before the last one that broke). After this I decided to just setup a more minimal repro environment, unfortunately I kinda failed at doing that because I overwrote my install of the NVENC refactor build, so the new |
Mh I wonder if that's the same deadlock with the threaded writer that #10597 is supposed to fix, but I applied that patch here, so maybe that won't quite fix it :/ This also affects the regular FFmpeg muxer output, but the writer is a separate process entirely there, so it deadlocking doesn't break OBS itself. But can result in fun things like you discovering several hours or even days later (if you don't reboot) that one of your video files is still locked by a stray I'll add some more logging to see if that is the case for you Edit: So far haven't been able to reproduce it :/ Hopefully the additional logging will provide some clarity on the matter. Edit 2: I was able to reproduce it, it's not a deadlock but a busy loop. Seems like somewhere the muxer sends a write with a size of |
435b7d0
to
50f9ce9
Compare
I've finally figured out what is happening and it is indeed my fault for not looking at the buffered writer from the ffmpeg muxer with enough thought. It requires any writes to be |
825bbcf
to
989597e
Compare
With yesterday's updates Opus audio is now also supported, meaning we've reached feature parity with the existing MP4 output via the ffmpeg muxer. I've now updated the UI part so it's available in simple mode and changed the description slightly. With that my plan would be the following (with no specific timeline):
|
I hope this isn't distracting for me to post this, but I tried it and it worked for me. I have this sample video I recorded on Windows 10 (using the PR's CI binary), and it's playing back okay for me in Windows 10's default player, VLC and mpv (on Windows 10 & macOS 10.15), Quick Look (spacebar in Finder) and QuickTime Player (macOS). As well as in Firefox (Windows 10 and macOS 10.15). It has the duration and basic metadata in Windows' file Explorer, which is nice. Sample video file made using the custom muxer (click to expand):View_of_the_Earth_from_the_ISS_Custom_Muxer_MP4.mp4Re-encode of some public domain NASA footage from here: https://commons.wikimedia.org/wiki/File:View_of_the_Earth_from_the_ISS_(8K).webm If there's anything else basic you want tested, I can try to do so. I can see if a relative can open it in their Adobe suite if I get a chance as well. But it seems to be a "normal MP4" for most intents/purposes, I suppose. Thanks for working on this! EDIT to add: I found ImHex on Windows to be helpful as a hex editor, as it understands MP4 structure and can color-highlight and deal with the different data sections accordingly. Perhaps the Ubuntu version of ImHex also does this. (The macOS version of ImHex doesn't do the special MP4 parsing, I don't think.) |
801f779
to
4f60ab0
Compare
Another week another update:
Custom options currently are:
|
850ebda
to
764abd9
Compare
Smaller update:
|
Hopefully final update for the first revision, primarily adding, updating and cleaning up comments plus a few smaller changes:
|
Description
Adds a native MP4 muxer/output to OBS.
Also adds a buffered file serializer, based on
ffmpeg-mux
I/O buffer implementation and seeking support for the existing array serializerCurrently supported Features:
Coming later in separte PRs:
Motivation and Context
The goals of this is to fix the drawbacks that resulted in fragmented MP4 no longer being the default (#10482).
To address those muxer creates something I call - for the lack of a better term - "Hybrid MP4":
This gives us the best of both worlds, a resilient and recoverable output file with great compatibility.
Technical description
ISO-BMFF/MP4/QuickTime use a common format for data that is pretty simple at it's heart.
The file is made up of boxes ("atoms" in Apple terminology) that have a size and four letter name, e.g.
moov
.When a file is written most of the audio and video data will live in data boxes (
mdat
) which do not have a defined structure. To be able to read and decode a file it is necessary to parse the movie boxe(s) (moov
/moof
).Generally speaking, a standard MP4 file has three boxes:
ftyp
Headermoov
Movie boxmdat
Audio/Video DataSince the contents of the
moov
box depend on the data inmdat
it is often written at the end, rather than the beginning. But this also means that if a file is incomplete, e.g. due to a crash or medium error, it generally cannot be read, as themdat
data by itself does not have any structure or meaning.In order to allow for streaming of MP4 files while they are being written some additions were made in form of the
moof
atom, which allows the leadingmoov
to be incomplete and not contain any information about the a/v data. Instead, it only contains the bare minimum of information necessary to setup a decoder. The data is then split into fragments, each of which starts with amoof
box, that can be decoded by combining the data from themoov
box with themoof
box.A fragmented MP4 file will thusly look like so:
-
ftyp
Header-
moov
Movie Box (without sample information)-
moof
Movie Fragment Box-
mdat
Fragment Audio/Video data-
moof
Movie Fragment Box-
mdat
Fragment Audio/Video Data- ...
While this format is great for streaming and resilience (it does not need a final
moov
to be written to be readable), it has significant downsides for casual users. For once, playback requires reading allmoof
boxes to get an accurate duration, which can take a long time on HDDs or network drivers, and some software straight up doesn't support this. While fragmented files can be turned into regular ones, this also requires double the space and can take a while depending on how fast the medium is.This is where this "hybrid MP4" approach comes in: It can turn a fragmented MP4 file into a regular one by merely writing 44 or 52 bytes (depending on video data size) at the start!
The hybrid MP4 file structure is as follows:
-
ftyp
Header-
free
Placeholder-
moov
Movie Box (without sample information)-
moof
Movie Fragment Box-
moof
Movie Fragment Box-
mdat
Fragment Audio/Video data-
moof
Movie Fragment Box-
mdat
Fragment Audio/Video Data- ...
-
moov
Movie Box (with sample information)Now in order to make this file appear as though it is a regular MP4 file all we need to do is overwrite the
free
box's size and name so that it becomes anmdat
box that spans the entire file up to our finalmoov
box, thus making the file appear as such:ftyp
Headermdat
Audio/Video Datamoov
Movie boxWe have essentially just hidden the fragmented structure of the file by turning the entire thing into one giant data box that the muxer will not try to parse. Simple as that!
Or to put it into layman's terms:
Future considerations
By having a custom muxer we are more flexible with how we write data to disk, and could adapt new container or codec features more quickly in the future.
This also lays groundwork for upcoming protocols such as Media over QUIC which will likely make use of CMAF which is a subset of ISO BMFF/MP4.
How Has This Been Tested?
Recorded more videos and spent more time in hex editors than I care to admit.
Types of changes
Checklist: