MP3 Frame Header Importing

closed account (iTR21hU5)
Hey everyone, been tearing my hair out overnight with this one and finally decided I'd try and get some help online.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

/* some useful headers */
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

//my headers
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>

using namespace std;

/* these values for bitrates and frequencies might come in useful */
unsigned int bitrate[] = {0,32000,40000,48000,56000,64000,80000,96000,112000,128000,160000,192000,224000,256000,320000,0};
unsigned int freq[]    = {44100,48000,32000,00000};

/* this is the function we're looking to call, with the values you have calculated */
void printmp3details(unsigned int nFrames, unsigned int nSampleRate, double fAveBitRate)
{
    printf("MP3 details:\n");
    printf("Frames: %d\n", nFrames);
    printf("Sample rate:%d\n", nSampleRate);
    printf("Ave bitrate:%0.0f\n", fAveBitRate);
}


//function to output sample frequency based on binary input
int calcsamprate(string inputbinary)
{
	if(inputbinary == "00")
		return(freq[0]);
	else if(inputbinary == "01")
		return(freq[1]);
	else if(inputbinary == "10")
		return(freq[2]);
	else
	{
		cerr << "incorrect sample frequency rate found in header" << endl;
		exit(1);
	}
}

//function to output bitrate of frame based on binary input
int calcbitrate(string inputbinary)
{
	if(inputbinary == "0000")
		return(freq[0]);
	if(inputbinary == "0001")
		return(freq[1]);
	if(inputbinary == "0010")
		return(freq[2]);
	if(inputbinary == "0011")
		return(freq[3]);
	if(inputbinary == "0100")
		return(freq[4]);
	if(inputbinary == "0101")
		return(freq[5]);
	if(inputbinary == "0110")
		return(freq[6]);
	if(inputbinary == "0111")
		return(freq[7]);
	if(inputbinary == "1000")
		return(freq[8]);
	if(inputbinary == "1001")
		return(freq[9]);
	if(inputbinary == "1010")
		return(freq[10]);
	if(inputbinary == "1011")
		return(freq[11]);
	if(inputbinary == "1100")
		return(freq[12]);
	if(inputbinary == "1101")
		return(freq[13]);
	if(inputbinary == "1110")
		return(freq[14]);
	if(inputbinary == "1111")
		return(freq[15]);
	else
	{
		cerr << "incorrect bitrate found in header" << endl;
		exit(1);
	}
}

void calculatedetails(ifstream & file)	//function taking inputfilestream as argument to calculate required information and call printmp3details
{
	file.seekg(0, ios::end);			// obtain filesize in bits
    size_t filesize = file.tellg();		// 

    string mp3contents;					//create string and allocate correct amount of memory
    mp3contents.reserve(filesize);		//
    
	char * buffer;						//array of characters to transfer binary data prior to copying to string
	buffer = new char [filesize];		//dynamically allocate memory

	file.seekg(0, ios::beg);			//transfer binary data from file to buffer array
	file.read(buffer, filesize);		//
	file.close();						//

	int filebitsize = filesize *8;
	char * bitstorage;
	bitstorage = new char [filebitsize];

	for(unsigned int i = 0; i < filesize; i++)
	{
		for(int k = 0; k < 8; k++)														
		{
			bitstorage[(i*8)+k] = (buffer[i] >> k) & 1; //convert from bytes to bits
		}
	}
	mp3contents.append(bitstorage);

	delete [] buffer;						//delete data from dynamically allocated memory
	delete [] bitstorage;

	vector<int> framepositions;			//vector to store location in string of all frames

	size_t searchpos = 0;
	string searchterm = "111111111111";
	int j = 0;
	while(mp3contents.find(searchterm, searchpos) != -1)			// while loop to find beginning of all frames in string and store their starting positions in vector
	{
		j++;
		framepositions.push_back(mp3contents.find(searchterm, searchpos));
		searchpos = framepositions[j] + 12;
	}

	string sampleratebinary = mp3contents.substr(framepositions[0] + 21, 2); //create substring containing sample rate info in binary

	int ongoingtotal = 0;
	for(unsigned int i = 0; i < framepositions.size(); i++)					// for loop to find all values of bitrate and add them all together
	{
		string bitratesubstr = mp3contents.substr(framepositions[i] + 17, 4);
		ongoingtotal = ongoingtotal + calcbitrate(bitratesubstr);
	}
	ongoingtotal = ongoingtotal/framepositions.size(); //averaging line

	printmp3details(framepositions.size(), calcsamprate(sampleratebinary), ongoingtotal);
}

/* Main function */
int main(int argc, const char* argv[])
{
	if(argc != 2)									//check correct number of command line arguments entered
	{
		cerr << "filename not included correctly" << endl;
		return(1);
	}

	const char* filename = argv[1];					//take first command line argument (apart from program name) as filename of mp3 to be opened

	ifstream mp3file(filename, ios::binary);		//open mp3 "filename" using binary i/o mode

	if(mp3file.fail() == true)						//check file opens correctly
	{
		cerr << "file failed to open" << endl;
		return(1);
	}
	
	calculatedetails(mp3file);						//call function to calculate required details
	
	return(0);
}


The bit that's giving me issues is the "calculatedetails" function, where an mp3 file is opened in binary and then an array of chars is filled with the binary data.

The problem I'm having is that I want to be able to read the constituent bits of the characters in, so that I can find the mp3 frame headers (12 1's in succession)

I'm aware that the section I've added in to perform this is incorrect, has anyone got an idea as to a better way to do this?
Last edited on
The mistake is basically this:
 
char MyBinaryValue = 1;

Do you spot the problem? What if I tell you it should be this:
 
char MyBinaryValue = '1';

For your usage, it better be this instead:
 
char MyBinaryValue = '0' + ( 1 );



(Line 111)
Last edited on
closed account (iTR21hU5)
Ah, thanks I'll see if that sorts it.
closed account (iTR21hU5)
Still having problems, I changed the " & 1 " on line 111 to "& '0' + (1)" like you suggested and it still appears to be failing to do what I want it to.

I added a debug code to cout the mp3contents string (what should at that point be a hell of a lot of 1s and 0s) and the output is two smiley faces and an arrow -.-
closed account (iTR21hU5)
On further inspection, if I cout the contents of the array the binary file was read into the output is simple "ID3" and a heart symbol. I would have expected a 20mb mp3 file to contain a bit more data than that..
No, that's not how you do it.
This is it.
 
bitstorage[(i*8)+k] = '0' + ((buffer[i] >> k) & 1);


And obviously cout won't help you, it will only display printable characters.
Last edited on
closed account (iTR21hU5)
Ah of course. I've made the modification anyway and it's still giving me a vector subscript out of range error, I assume due to the loop designed to find the "111111111111" still not finding anything and so not filling in the vector storing frame locations with anything.
This is a working mp3 frame parser written in C found on the internet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

int main()
{
	FILE* pFile;
	errno_t err;
	unsigned int uiFrame           = 0,
		check              = 0,
		test               = 0,
		CheckFlag          = 0,
		cntSize            = 0,
		uiFrameCount       = 1,
		PrevoiusFrameSize  = 0,
		TotalFileSize      = 0;

	int bitrate[16] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0};
	int samp_freq[4]= {44, 48, 32, 0};

	if( 0 != (err  = fopen_s( &pFile, "C:\\test.mp3", "rb" )) ) {
		printf( "The input file was not opened\n" );
		return 1;
	}
	fseek(pFile, 0, SEEK_END);
	TotalFileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	while(cntSize < TotalFileSize/*10 > uiFrameCount*/)
	{
		// Check for the SynBits
		do 
		{
			uiFrame = getc(pFile);
			if(EOF == uiFrame)
				break;
			cntSize++;
			if(0xFF == uiFrame)
			{
				uiFrame = getc(pFile);
				if(EOF == uiFrame)
					break;
				if((0xFA == uiFrame) || (0xFB == uiFrame))
				{
					if(1 != uiFrameCount)
						printf("\nFrame Size is %d \n\n",cntSize - PrevoiusFrameSize);

					printf("\nFrame Found at Byte %d", cntSize);
					PrevoiusFrameSize = cntSize;
					CheckFlag         = 1;
					uiFrameCount++;
				}
				cntSize++;
			}
		}while(1 != CheckFlag);

		CheckFlag = 0;

		//Check for MPEG Version
		check = uiFrame & 0x08;
		switch(check)
		{
		case  0x00:
			printf("\nError");
			break;
		case  0x08:
			printf("\nMPEG 1");
			break;
		}

		//Check for Layer
		check = uiFrame & 0x06;
		switch(check)
		{
		case  0x00:
			printf("\nReserved");
			break;
		case  0x02:
			printf("\nLayer 3");
			break;
		case  0x04:
			printf("\nLayer 2");
			break;
		case  0x06:
			printf("\nLayer 1");
			break;
		}

		//CRC Added or not
		test = uiFrame & 0x01;
		switch(test)
		{
		case  0x00:
			printf("\nRedundancy Added");
			break;
		case  0x01:
			printf("\nRedundancy Not Added");
			break;
		}

		// get next byte
		uiFrame = getc(pFile);
		if(uiFrame == EOF)
			break;
		cntSize++;

		// Check for Bit rate
		check = uiFrame & 0xF0;
		test = check >> 4;
		printf("\nBitrate is %d\n",bitrate[test]);

		// Check for Sampling Frequency
		check = uiFrame & 0x0C;
		test = check >> 2;
		printf("Sampling Frequency is %d\n",samp_freq[test]);

		// Check slot for bitrate change
		check = uiFrame& 0x02;
		switch(check)
		{
		case  0x00:
			printf("No Slot to adjust bit rate");
			break;
		case  0x02:
			printf("Slot to adjust bit rate");
			break;
		}

		// Check private bit
		check = uiFrame & 0x01;
		printf("\nPrivate Bit is %d\n", check);

		// Get next byte
		uiFrame = getc(pFile);
		if(uiFrame == EOF)
			break;
		cntSize++;
		// Check for channel type
		check = uiFrame & 0xC0;
		switch(check)
		{
		case  0x00:
			printf("Stereo");
			break;
		case  0x40:
			printf("Joint Stereo");
			break;
		case  0x80:
			printf("Dual Channel");
			break;
		case  0xC0:
			printf("Single Channel");
			break;
		}

		// Intensity and MS Stero Check
		check = uiFrame & 0x30;
		test = check >> 4;
		switch(test)
		{
		case  0x00:
			printf("\nIntensity Stereo-OFF MS Stereo-OFF");
			break;
		case  0x10:
			printf("\nIntensity Stereo-ON MS Stereo-OFF");
			break;
		case  0x20:
			printf("\nIntensity Stereo-OFF MS Stereo-ON");
			break;
		case  0x30:
			printf("\nIntensity Stereo-ON MS Stereo-ON");
			break;
		}

		// Check for Copyright
		check = uiFrame& 0x08;
		switch(check)
		{
		case  0x00:
			printf("\nNo Copyright");
			break;
		case  0x08:
			printf("\nCopyrighted");
			break;
		}

		// Check for Original or Copy
		check = uiFrame & 0x04;
		switch(check)
		{
		case  0x00:
			printf("\nCopy");
			break;
		case  0x04:
			printf("\nOriginal");
			break;
		}

		// Check for Emphasis
		check = uiFrame& 0x03;
		switch(check)
		{
		case  0:
			printf("\nNo Emphasis");
			break;
		case  1:
			printf("\n50/15 Micro seconds");
			break;
		case  2:
			printf("\nReserved");
			break;
		case  3:
			printf("\nCCITT J.17");
			break;
		}
		_getch();
	}

	printf("\nTotal Number of Frames displayed is %d \n", uiFrameCount);
	fclose(pFile);
}
Topic archived. No new replies allowed.