This MR is marked as draft as it is dependent on MR !7493.
It adds two new resolver hints for the mp3 format: 1. The [MP3 frame header][1]; and 2. The [ID3v2.3 tag][2]
I have two issues: 1. The MP3 frame header only has 14 bits enabled in the mask; and 2. ID3v2.3 tags aren't exclusive to mp3
Hence I'm raising this now for early feedback/ideas. As the game I'm looking to fix (ProgressBar95) includes MP3s with both these headers, but it uses a custom [IMFByteStream implementation][3] that doesn't provide any `IMFAttributes` interface. So I think probing the stream is the only way to determine these are mp3 files.
[1]: http://www.mp3-tech.org/programmer/frame_header.html [2]: https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.3.0.html [3]: https://github.com/darkf/almixer/blob/8ac8408ca367bc068fcc69140b32536a282603...
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/mfplat/main.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index abc998cf513..01d9d2ddd89 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6207,14 +6207,18 @@ static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD f
static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR const **url) { - static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c}; - static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '}; - static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; - static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00}; - static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00}; - static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00}; - static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00}; - static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}; + static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c}; + static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '}; + static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; + static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00}; + static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00}; + static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00}; + static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00}; + static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}; + static const unsigned char mp3magic[] = {0xff,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char mp3mask[] = {0xff,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char idv2_3_magic[] = {'I','D','3',0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char idv2_3_mask[] = {0xff,0xff,0xff,0xff,0x00,0x1f,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00}; static const struct stream_content_url_hint { const unsigned char *magic; @@ -6229,6 +6233,8 @@ static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR con { mp42magic, L".mp4", mp4mask }, { mp4_magic, L".mp4", mp4mask }, { mp4vmagic, L".m4v", mp4mask }, + { mp3magic, L".mp3", mp3mask }, + { idv2_3_magic, L".mp3", idv2_3_mask }, }; unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)]; IMFAttributes *attributes;
If it's a good first guess to treat IDv2 tags as MP3, I see no problem starting with that.
MR !7493 has been merged, so I'm marking this one as ready. Whilst false positives are theoretically possible, it should be unlikely. Short of implementing more sophisticated probing, I think this is the best I can do. I've ensured the MP3 checks come last, so it won't be possible for false positives to occurs with the prior formats. And although ID3 tags can appear in other formats, in practice it seems they are almost exclusively used in the MP3 format.
On Mon Mar 10 12:44:26 2025 +0000, Brendan McGrath wrote:
MR !7493 has been merged, so I'm marking this one as ready. Whilst false positives are theoretically possible, it should be unlikely. Short of implementing more sophisticated probing, I think this is the best I can do. I've ensured the MP3 checks come last, so it won't be possible for false positives to occurs with the prior formats. And although ID3 tags can appear in other formats, in practice it seems they are almost exclusively used in the MP3 format.
More sophisticated probing will have to read IDv2 format, looking for data section tags I guess. It's not impossible to do, but I agree that we'll need a use case first. I don't think there is a separate concept of containers formats and media formats that they can contain, so I can imagine it could be using some stripped down version of IDv2 parser to resolve types and then the full thing (if there is metadata support at all for mp3), in specific sources.
On Mon Mar 10 12:44:26 2025 +0000, Nikolay Sivov wrote:
More sophisticated probing will have to read IDv2 format, looking for data section tags I guess. It's not impossible to do, but I agree that we'll need a use case first. I don't think there is a separate concept of containers formats and media formats that they can contain, so I can imagine it could be using some stripped down version of IDv2 parser to resolve types and then the full thing (if there is metadata support at all for mp3), in specific sources.
I was thinking the same thing. If a use case does present, I guess we can look at what FFmpeg and GStreamer do for ideas, or even just the plain old `file` command, as it detects MP3 with ID3v2 tags as well. Example: ``` Audio file with ID3 version 2.3.0, contains: MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Monaural ```
This merge request was approved by Nikolay Sivov.