Recognize and skip invalid (or proprietary?) MP3 frame headers from web audio streams

I am writing an MP3 decoder (not for sound reproduction, but for frequency analysis).

I can successfully identify the ID3v1 and ID3v2 tags and loop them through their entire length (including ID3v2 NULs debugging) because I am not interested in that metadata. I'm right after the frequencies.

I can also get and correctly interpret all the headers of the MP3 frames (do all the tests available, of which there are not many). A short excerpt from a nearby window telling me what the matter is about:

...
2131 until pos. 2226975 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2132 until pos. 2228020 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2133 until pos. 2229065 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2134 until pos. 2230110 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2135 until pos. 2231155 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2136 until pos. 2232200 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2137 until pos. 2233245 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
2138 until pos. 2234290 FFFBE264, EMp3Vrs1, EMp3LayIII, 320, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 1009 B
...

      

If I take the MP3 frames along their entire length (including CRC if any, side information, Huffman encoded data, and ancillary data if any) and write them back to a FileStream object, naming it .mp3, I can hear the name just fine.

This works for MP3 files stored locally or somewhere on the local network, and there is no bad header encountered, not one false alarm. Success.

Enters a web stream . If I feed this to my FileStream object everything works fine for a few hundred frames, but all of a sudden a lot of invalid frames are being streamed:

...
1291 FFFB9264, EMp3Vrs1, EMp3LayIII, 128, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 382 B
1292 FFFB9244, EMp3Vrs1, EMp3LayIII, 128, 44100, 1, EMp3ChMJointStereo, 0, CRC: 0, Data: 382 B
1293 FFFB9264, EMp3Vrs1, EMp3LayIII, 128, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 382 B
1294 FFFB9264, EMp3Vrs1, EMp3LayIII, 128, 44100, 1, EMp3ChMJointStereo, 2, CRC: 0, Data: 382 B
34B5FF96 is not a valid header
FF96C517 is not a valid header
FFFFFFF8 is not a valid header
FFFFF8F1 is not a valid header
FFF8F1E1 is not a valid header
1295 FFF32191, EMp3Vrs2, EMp3LayIII, 16, 22050, 0, EMp3ChMDualChannel, 1, CRC: 0, Data: 68 B
There are 136 B of pre-header-data
...

      

These invalid headers are followed by a variable length sequence of unrecognized bytes until the next valid header appears.

Here is a hex dump of the part of the stream in question:

0008-40a0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-40b0:  00 00 00 00-00 00 00 34-b5 ff 96 c5-17 59 00 ca  .......4 .....Y.. <- 34B5FF96, FF96C517
0008-40c0:  00 a0 00 67-00 08 00 4f-00 1e 00 1f-00 e2 00 b3  ...g...O ........
0008-40d0:  00 ac 00 cf-00 69 00 bf-00 ff ff ff-f8 f1 e1 d0  .....i.. ........ <- FFFFFFF8, FFFFF8F1, FFF8F1E1
0008-40e0:  00 a0 00 e0-00 78 00 5d-00 c3 00 00-00 09 00 83  .....x.] ........
0008-40f0:  00 20 00 04-00 80 00 dd-00 d0 00 45-00 08 00 80  ........ ...E....
0008-4100:  00 26 00 96-00 c5 00 ed-00 18 00 9c-00 a7 00 a9  .&...... ........
0008-4110:  00 f5 00 1c-00 81 00 43-00 d8 00 61-00 78 00 ed  .......C ...a.x..
0008-4120:  00 d0 00 91-00 7f 00 a8-00 93 00 2a-00 2e 00 a2  ........ ...*....
0008-4130:  00 20 00 ee-00 a3 00 e9-00 35 00 75-00 77 00 ff  ........ .5.u.w.. <- FFF32191
0008-4140:  f3 21 91 19-0c da 9d 48-96 be 61 e2-cc db 5d d1  .!.....H ..a...].
0008-4150:  cd 40 8b bb-a3 8a 22 9e-26 65 36 aa-47 90 63 e2  .@....". &e6.G.c.
0008-4160:  46 72 21 fe-cb 78 0a 08-f1 48 24 da-89 25 55 78  Fr!..x.. .H$..%Ux
0008-4170:  6a 39 d2 65-68 11 14 6d-41 bb b5 45-91 05 3d b0  j9.eh..m A..E..=.
0008-4180:  03 18 4b 39-fb c2 dd 01-8e 95 15 34-39 93 b9 1f  ..K9.... ...49...
0008-4190:  47 c4 bf d8-61 04 85 08-a0 41 8c ca-7b b9 19 aa  G...a... .A..{...
0008-4197:  93 05 18 50-5c 51 d7                             ...P\Q.

      

I'm assuming TuneIn carries some metadata here, but I can't figure out which protocol to use , if any.

The problem is that these blocks are obviously taking up more bytes than I think because the next header I think is valid is an invalid header (FFF32191 does not fit the 128Kbps 44100Hz JointStereo model used in others frames), and therefore will probably still belong to this possible piece of metadata.

I'm pretty sure about that, because by saving these MP3 frames as well, as in local files, they play just fine (as if I were recording from the Internet, therefore only with 128 Kbps), as long as the errors appear after several hundred frames. Then there is intermittent noise, crushing and whistling of only a few decibels.

The depressing thing: if I play the same URL from in the browser, it plays just fine .

My question is: What do those browsers know that I cannot understand? (I just want to skip the correct number of bytes to get the next valid frame.)

(At one time I was so upset that I thought completely unreasonably that TuneIn was inserting these bytes viciously to prevent people like me from recording "their" music. But then: browsers know how to deal with these streams, therefore. .. apologies to TuneIn.)


Edit

Analyzing the dump a little back, I found interesting content, namely the ASCII string with the inscription "LAME3.98.4".

0008-3d70:  9c 5f 26 ff-fb 92 64 fb-80 03 07 64-5d eb 0b 39  ._&...d. ...d]..9 <- FFFB9264 (frame 1293)
0008-3d80:  fe 60 89 ab-1d 41 87 1e-0a e1 2f 75-e6 24 a7 e9  .`...A.. ../u.$..
0008-3d90:  75 a6 2d 28-f2 9a ba 2c-23 07 79 68-e8 94 18 a4  u.-(..., #.yh....
0008-3da0:  68 d4 08 0e-f0 48 35 67-7e d2 ef 9e-73 13 ba a5  h....H5g ~...s...
0008-3db0:  fc f2 db d9-07 28 6c ce-3a 15 cb cf-39 af 99 5d  .....(l. :...9..]
0008-3dc0:  25 22 89 19-7c c4 22 a2-3b 51 e9 a7-ff ff ff f4  %"..|.". ;Q......
0008-3dd0:  59 83 1a 84-53 85 d6 99-25 20 49 8b-18 7f 25 5e  Y...S... %.I...%^
0008-3de0:  cd 41 69 75-e5 86 d6 8e-39 a3 96 1c-45 9e 69 66  .Aiu.... 9...E.if
0008-3df0:  d5 a6 b4 6d-e9 99 46 96-eb a3 73 74-4f de f2 96  ...m..F. ..stO...
0008-3e00:  34 48 60 70-10 5c 5f d9-2e dd af 44-2c c5 5a 48  4H`p.\_. ...D,.ZH
0008-3e10:  51 64 63 0d-92 af 62 0f-bb 55 ae b4-9d d1 8a f6  Qdc...b. .U......
0008-3e20:  66 41 e8 c3-68 54 ae 6d-0e 13 32 aa-bd ff ff f1  fA..hT.m ..2.....
0008-3e30:  56 00 4b 2a-24 49 25 15-98 77 98 71-36 d7 2d c2  V.K*$I%. .w.q6.-.
0008-3e40:  29 ce 8a b5-1b 72 84 e9-3f 03 4a da-74 e4 66 29  )....r.. ?.J.t.f)
0008-3e50:  fc 7d e7 fd-53 68 f4 7e-3b bb 2e 1b-97 e1 f1 8a  .}..Sh.~ ;.......
0008-3e60:  ba fd da 8b-8e 73 96 3c-20 40 ce 13-53 20 f0 6a  .....s.< .@..S..j
0008-3e70:  6d 9d cf c6-fa 84 f1 48-84 67 ef 51-af 8c ec 9f  m......H .g.Q....
0008-3e80:  7f ff ce 15-32 ca b1 ac-f5 e5 48 e8-0c 38 23 c3  ....2... ..H..8#.
0008-3e90:  05 02 b5 55-4c 41 4d 45-33 2e 39 38-2e 34 55 55  ...ULAME 3.98.4UU <- LAME3.98.4
0008-3ea0:  55 55 08 83-c5 04 58 55-e4 b3 30 3a-c9 da 85 3d  UU....XU ..0:...=
0008-3eb0:  11 80 7d 6d-62 41 5b d8-42 9a c2 a0-56 72 77 83  ..}mbA[. B...Vrw.
0008-3ec0:  4a d4 79 4b-28 de 4c 7f-2d 2c 7d b9-e0 bb 1d d8  J.yK(.L. -,}.....
0008-3ed0:  b6 fd b6 f3-ed 9a ba 09-49 00 6d 5f-fd 8a 77 cf  ........ I.m_..w.
0008-3ee0:  df 3f f4 70-3a 29 1c 4a-b7 39 6f 15-8c 74 fa fa  .?.p:).J .9o..t..
0008-3ef0:  f3 be 67 1f-db ae 2e 5e-90 dd 74 9c-ae 76 82 c1  ..g....^ ..t..v..
0008-3f00:  7b 3d 6a 03-05 0e aa a7-41 d6 df ff-ff 14 1a e3  {=j..... A.......
0008-3f10:  d8 a2 52 42-09 ff fb 92-64 f8 00 02-ff 4d 57 e1  ..RB.... d....MW. <- FFFB9264 (frame 1294)
0008-3f20:  e5 35 e0 4e-a9 7b dc 2c-c2 7f cb b5-31 75 a7 95  .5.N.{., ....1u..
0008-3f30:  35 f1 88 25-ec f4 f3 0e-73 a0 c0 6d-ee a0 bf 15  5..%.... s..m....
0008-3f40:  d8 b9 5d 7d-ce d4 c5 84-5a 4a 97 15-ba 22 08 09  ..]}.... ZJ..."..
0008-3f50:  b8 ec e8 3f-b1 22 89 b0-72 6d d7 db-75 b7 3b f4  ...?.".. rm..u.;.
0008-3f60:  b7 56 dd e3-43 0e 36 99-33 00 00 00-00 00 00 00  .V..C.6. 3.......
0008-3f70:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3f80:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3f90:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3fa0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3fb0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3fc0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3fd0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3fe0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-3ff0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4000:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4010:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4020:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4030:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4040:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4050:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4060:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4070:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4080:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-4090:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........
0008-40a0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ........ ........ <- Start of above dump
0008-40b0:  00 00 00 00-00 00 00 34-b5 ff 96 c5-17 59 00 ca  .......4 .....Y.. <- Invalid header

      

LAME 3.98.4 is dated 2010-04-14. However, what is he doing there? Answer: This is ok, see Brad's comment in his answer.

0


source to share


2 answers


It was difficult to decide.

When it comes to reading a piece in Huffman encoded data at its pre-calculated length (with MP3 using 128 kbps and 44.1 kHz, which is 381 or 382 B), I relied on the fact that IO.Stream

synchronous Read()

is actually synchronous and waits for the number of requested bytes to be available (as my smart books say that when fewer bytes are received, the stream ended). Since the address is a web stream, bytes are sent regularly. Thus, I wrote:

            ReDim gabMainData(0 To iDataSize - 1)
            s.Read(gabMainData, 0, iDataSize)

      

It turns out that everything from time to time (first after a few hundred, but up to 1200 frames) Read

may return fewer bytes - even though the web stream hasn't ended at all - leaving a lot of NUL bytes at the end of a suitably reduced byte array.

In these cases, using an additional ReadByte()

will help:



            ReDim gabMainData(0 To iDataSize - 1)
            iNumRead = s.Read(gabMainData, 0, iDataSize)
            Do While iNumRead < iDataSize
                iByte = s.ReadByte()
                If iByte = -1 Then
                    'End of stream activities.
                    ...
                End If
                gabMainData(iNumRead) = CByte(iByte)
                iNumRead += 1
            Loop

      

The test after this fix reports 100,000 frames without a single click, just as if it were a CD, so I'm pretty sure of that.

Now let's do this standard method Read()

.

If there is a better way to accomplish this task in sync, please kindly let me know.

+2


source


I'm assuming TuneIn is carrying some metadata here, but I can't figure out which protocol to use, if any.

This has nothing to do with TuneIn ... it's a SHOUTcast server and it uses ICY style metadata. In any case, unless you really ask for the metadata (with Icy-MetaData: 1

in the HTTP request headers), you won't get it. You will get a normal raw MPEG stream.

If you'd like to know more about data, check out my answers here:

I don't see SHOUTcast style ICY metadata in your dump.

everything goes well for a few hundred frames, but suddenly a lot of invalid frames appear



Interestingly, it works initially, but then fails.

Typically, for these streams, the first pairs of frames are inconvenient because the server does not need to know or care about the data passing through it. It has a fixed buffer size of 128KB or so and randomly blocks, so when a client connects, it receives that buffer plus whatever comes after it. That is, the client "needle dropped" straight into the stream and is expected to sync.

This is done using the word sync 0xFFF*

or 0xFFE*

. Anything that is required before syncing should be discarded. Any frames requiring an inaccessible bit reservoir should be discarded. Eventually, after a few frames, you will have a steady stream of data to decode.

Double check to make sure you don't have a buffer around the previous file / url, then re-sync with the stream on initial connection.

If that's not a problem, I honestly don't know what to suggest, other than that some stations are using broken codecs. You'd be surprised how many internet radio stations use copies of LAME from 15 years ago.

I could also suggest, if possible, stick to the existing codec and do the analysis after converting it to regular PCM.

+2


source







All Articles