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
|
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mp3dec.h"
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN)
int16_t audiodata[MAX_BUFFER_LEN];
typedef struct {
char *ptr, *end;
} stream;
#define READ_PTR(stream) ((void*)((stream)->ptr))
#define BYTES_LEFT(stream) ((stream)->end - (stream)->ptr)
#define CONSUME(stream, n) ((stream)->ptr += n)
void skip_id3v2(stream* self) {
if (BYTES_LEFT(self) < 10) {
return;
}
uint8_t *data = READ_PTR(self);
if (!(
data[0] == 'I' &&
data[1] == 'D' &&
data[2] == '3' &&
data[3] != 0xff &&
data[4] != 0xff &&
(data[5] & 0x1f) == 0 &&
(data[6] & 0x80) == 0 &&
(data[7] & 0x80) == 0 &&
(data[8] & 0x80) == 0 &&
(data[9] & 0x80) == 0)) {
return;
}
uint32_t size = (data[6] << 21) | (data[7] << 14) | (data[8] << 7) | (data[9]);
size += 10; // size excludes the "header" (but not the "extended header")
CONSUME(self, size + 10);
}
bool mp3file_find_sync_word(stream* self) {
int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
if (offset >= 0) {
CONSUME(self, offset);
return true;
}
return false;
}
void fatal(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); }
void perror_fatal(const char *msg) { perror(msg); exit(1); }
bool probable_overflow(int16_t a, int16_t b) {
if(a > 32700 && b < -32700) {
return true;
} else if(b > 32700 && a < -32700) {
return true;
} else {
return false;
}
}
void look_for_overflow(int16_t *ptr, size_t os, int frame) {
for(size_t i=2; i<os; i+=2) {
int16_t l_old = ptr[i-2];
int16_t l_new = ptr[i];
int16_t r_old = ptr[i-1];
int16_t r_new = ptr[i+1];
if(probable_overflow(l_old, l_new)) {
printf("probable overflow, left channel, frame %5d sample %5d, %5d\n", frame, (i/2)-1, i/2);
printf("Consecutive sample values: %5d %5d\n", l_old, l_new);
}
if(probable_overflow(r_old, r_new)) {
printf("probable overflow, right channel, frame %5d sample %5d, %5d\n", frame, (i/2)-1, i/2);
printf("Consecutive sample values: %5d %5d\n", r_old, r_new);
}
}
}
int main(int argc, char **argv) {
if(argc != 3) {
fprintf(stderr, "Decode MP3 into headerless LE16 stereo\n");
fprintf(stderr, "Usage: %s input.mp3 output.bin\n", argv[0]);
exit(99);
}
HMP3Decoder decoder = MP3InitDecoder();
FILE *fi = fopen(argv[1], "rb");
if(!fi) perror_fatal("open");
struct stat st;
if(fstat(fileno(fi), &st) < 0) perror_fatal("fstat");
stream s;
s.ptr = malloc(st.st_size);
if(!s.ptr) perror_fatal("malloc");
s.end = s.ptr + st.st_size;
if(fread(s.ptr, 1, st.st_size, fi) != st.st_size) perror_fatal("fread");
FILE *fo = fopen(argv[2], "wb");
if(!fo) perror_fatal("open");
skip_id3v2(&s);
int frame=0;
while(mp3file_find_sync_word(&s)) {
MP3FrameInfo fi;
int err = MP3GetNextFrameInfo(decoder, &fi, READ_PTR(&s));
if(err != ERR_MP3_NONE) fatal("MP3GetNextFrameInfo");
int bytes_left = (int)BYTES_LEFT(&s);
uint8_t *inbuf = READ_PTR(&s);
err = MP3Decode(decoder, &inbuf, &bytes_left,
audiodata, 0);
if(err != ERR_MP3_NONE) fatal("MP3Decode");
look_for_overflow(audiodata, fi.outputSamps, ++frame);
if(fwrite(audiodata, 1, fi.outputSamps*sizeof(int16_t), fo)
!= fi.outputSamps*sizeof(int16_t))
perror_fatal("fwrite");
CONSUME(&s, BYTES_LEFT(&s) - bytes_left);
}
return 0;
}
|