Last active
February 24, 2016 09:23
-
-
Save alenstarx/85581c6d4dfc29187acf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <mad.h> | |
#define ALOGE(...) printf(__VA_ARGS__);printf("\n") | |
struct buffer { | |
unsigned char const *start; | |
unsigned long length; | |
}; | |
/* | |
* This is the input callback. The purpose of this callback is to (re)fill | |
* the stream buffer which is to be decoded. In this example, an entire file | |
* has been mapped into memory, so we just call mad_stream_buffer() with the | |
* address and length of the mapping. When this callback is called a second | |
* time, we are finished decoding. | |
*/ | |
static | |
enum mad_flow input(void *data, | |
struct mad_stream *stream) | |
{ | |
struct buffer *buffer = data; | |
if (!buffer->length) | |
return MAD_FLOW_STOP; | |
mad_stream_buffer(stream, buffer->start, buffer->length); | |
buffer->length = 0; | |
return MAD_FLOW_CONTINUE; | |
} | |
/* | |
* The following utility routine performs simple rounding, clipping, and | |
* scaling of MAD's high-resolution samples down to 16 bits. It does not | |
* perform any dithering or noise shaping, which would be recommended to | |
* obtain any exceptional audio quality. It is therefore not recommended to | |
* use this routine if high-quality output is desired. | |
*/ | |
static inline | |
signed int scale(mad_fixed_t sample) | |
{ | |
/* round */ | |
sample += (1L << (MAD_F_FRACBITS - 16)); | |
/* clip */ | |
if (sample >= MAD_F_ONE) | |
sample = MAD_F_ONE - 1; | |
else if (sample < -MAD_F_ONE) | |
sample = -MAD_F_ONE; | |
/* quantize */ | |
return sample >> (MAD_F_FRACBITS + 1 - 16); | |
} | |
/* | |
* This is the output callback function. It is called after each frame of | |
* MPEG audio data has been completely decoded. The purpose of this callback | |
* is to output (or play) the decoded PCM audio. | |
*/ | |
static | |
enum mad_flow output(void *data, | |
struct mad_header const *header, | |
struct mad_pcm *pcm) | |
{ | |
unsigned int nchannels, nsamples; | |
mad_fixed_t const *left_ch, *right_ch; | |
/* pcm->samplerate contains the sampling frequency */ | |
nchannels = pcm->channels; | |
nsamples = pcm->length; | |
left_ch = pcm->samples[0]; | |
right_ch = pcm->samples[1]; | |
while (nsamples--) { | |
signed int sample; | |
/* output sample(s) in 16-bit signed little-endian PCM */ | |
sample = scale(*left_ch++); | |
//putchar((sample >> 0) & 0xff); | |
//putchar((sample >> 8) & 0xff); | |
//TODO save to pcm | |
if (nchannels == 2) { | |
sample = scale(*right_ch++); | |
//putchar((sample >> 0) & 0xff); | |
//putchar((sample >> 8) & 0xff); | |
//TODO save to pcm | |
} | |
} | |
return MAD_FLOW_CONTINUE; | |
} | |
/* | |
* This is the error callback function. It is called whenever a decoding | |
* error occurs. The error is indicated by stream->error; the list of | |
* possible MAD_ERROR_* errors can be found in the mad.h (or stream.h) | |
* header file. | |
*/ | |
static | |
enum mad_flow error(void *data, | |
struct mad_stream *stream, | |
struct mad_frame *frame) | |
{ | |
struct buffer *buffer = data; | |
fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", | |
stream->error, mad_stream_errorstr(stream), | |
stream->this_frame - buffer->start); | |
/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ | |
return MAD_FLOW_CONTINUE; | |
} | |
static | |
enum mad_flow header(void* data, struct mad_header const * hdr){ | |
ALOGE("layer: %d", hdr->layer); | |
ALOGE("mode: %d", hdr->mode); | |
ALOGE("extension: %d", hdr->mode_extension); | |
ALOGE("emphasis: %d", hdr->emphasis); | |
ALOGE("bitrate: %d", hdr->bitrate); | |
ALOGE("samplerate: %d", hdr->samplerate); | |
ALOGE("crc_check: %d", hdr->crc_check); | |
ALOGE("crc_target: %d", hdr->crc_target); | |
ALOGE("flags: %d", hdr->flags); | |
ALOGE("private_bits: %d", hdr->private_bits); | |
ALOGE("duration: %ld.%u", hdr->duration.seconds, hdr->duration.fraction); | |
return MAD_FLOW_CONTINUE; | |
} | |
/* | |
* This is the function called by main() above to perform all the decoding. | |
* It instantiates a decoder object and configures it with the input, | |
* output, and error callback functions above. A single call to | |
* mad_decoder_run() continues until a callback function returns | |
* MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and | |
* signal an error). | |
*/ | |
static | |
int decode(unsigned char const *start, unsigned long length) | |
{ | |
struct buffer buffer; | |
struct mad_decoder decoder; | |
int result; | |
/* initialize our private message structure */ | |
buffer.start = start; | |
buffer.length = length; | |
/* configure input, output, and error functions */ | |
mad_decoder_init(&decoder, &buffer, | |
input, header /* header */, 0 /* filter */, output, | |
error, 0 /* message */); | |
/* start decoding */ | |
result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); | |
/* release the decoder */ | |
mad_decoder_finish(&decoder); | |
return result; | |
} | |
int main(int argc, char** argv) | |
{ | |
if (argc != 2){ | |
printf("usage: %s file.mp3\n", argv[0]); | |
return 0; | |
} | |
int fd = open(argv[1], O_RDONLY); | |
if (!fd) { | |
ALOGE("fopen: %s", strerror(errno)); | |
//perror(path); | |
//exit(EXIT_FAILURE); | |
return 0; | |
} | |
struct stat sb; | |
if (stat(argv[1], &sb)) { | |
ALOGE("stat: %s", strerror(errno)); | |
//perror(path); | |
// exit(EXIT_FAILURE); | |
close(fd); | |
return 0; | |
} | |
void* file_buf = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); | |
if(!file_buf || file_buf == MAP_FAILED){ | |
ALOGE("mmap: %s", strerror(errno)); | |
close(fd); | |
return 0; | |
} | |
int rc = decode(file_buf, sb.st_size); | |
if (rc){ | |
ALOGE("decode"); | |
} | |
if(munmap(file_buf, sb.st_size) != 0){ | |
ALOGE("munmap: %s", strerror(errno)); | |
} | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment