Kethsar / ytarchive

Garbage Youtube livestream downloader
MIT License
1.01k stars 83 forks source link

Fix MP4 fragment writing to work with ffmpeg 6.1 #164

Closed Hakkin closed 7 months ago

Hakkin commented 8 months ago

ffmpeg 6.1 fails to parse concatenated MP4 files with multiple ftyp atoms, so we have to remove all but the first. Adds logic to pass the media mimetype through to the fragment downloader, previously the fragment downloader was trying to remove atoms from all fragments, including WEBM ones. This is pretty unlikely at actually cause issues unless by some freak chance the WEBM fragment has a valid MP4 atom in it, but figured I'd correct it anyways. Still falls back to removing from all fragments if the mimetype is blank for whatever reason.

I tested the mimetype detection with DASH and adaptive formats, both work fine, but I can't get raw Google video URLs to work (even on git master). Not sure if it's broken or I'm doing it wrong.

Hakkin commented 8 months ago

Can you show an example of what ffmpeg 6.1 does without these changes in place

It seems to just parse the first fragment of the concatenated file before throwing an error ("invalid data"), the resulting file ends up only being a second or two long.

If at all possible it would probably make future changes less of a pain if there's a way around it without actually adding all of the mime-type checks.

Actually it might even be better to instead just set a flag based on if the stream being downloaded is VP9 or h264

It specifically has to do with the container format, not the codec. So for example it also applies to AAC audio since YouTube uses MP4 for that. As far as I know, YouTube never actually serves Opus/WEBM audio for livestreams, so you probably could get away with just processing all audio fragments + all h264 fragments, but it's possible at some point in the future YouTube could change to using Opus or serving VP9 through MP4 or H264 through WEBM, or something like that. It's more robust to base it off the container mimetype rather than the codec.

The only actual mimetype check is for removing atoms, all the rest is just boilerplate for passing the mimetype from the manifests to the fragments, it's pretty much just replacing the "SetDownloadURL" with "SetStreamInfo", which is just a helper function that sets both the Download URL and Mimetype.

I'll fix the Mutex lock in the next commit.

Hakkin commented 7 months ago

I think I found a better way to do this, YouTube returns a Content-Type header on each fragment, the mimetype can just be gotten from that directly in the fragment downloader instead of passing it in from the manifest. That massively simplifies the logic and I can basically revert all the extra logic outside the fragment downloader.

Hakkin commented 7 months ago

Alright, reverted all the other code and just kept the RemoveAtoms function and getting the Content-Type header in the fragment downloader. Much cleaner now.