How to decode mp3 to pcm using lame? - c++

I'm looking for an example of how to decode mp3 to pcm using c++
I found an example that shows how to encode! And it works fine for me!
How about decode?
Thanks!!!
Encoding function:
#include <stdio.h>
#include <lame/lame.h>
int main(void)
{
int read, write;
FILE *pcm = fopen("file.pcm", "rb");
FILE *mp3 = fopen("file.mp3", "wb");
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
return 0;
}

Related

u-law compression returns invalid file c++

I'm trying to apply the u-law algorithm to a wav file file.wav, and then create a new file file2.wav.
file.wav has 16 bits/sample, and I want to obtain a file2.wav that has 8 bits/sample.
This is my code:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
using std::string;
using std::fstream;
typedef struct WAV_HEADER {
char RIFF[4];
unsigned long ChunkSize;
char WAVE[4];
char fmt[4];
unsigned long Subchunk1Size;
unsigned short AudioFormat;
unsigned short NumOfChan;
unsigned long SamplesPerSec;
unsigned long bytesPerSec;
unsigned short blockAlign;
unsigned short bitsPerSample;
char Subchunk2ID[4];
unsigned long Subchunk2Size;
} wav_hdr;
int headerSize = 0;
string path = "file.wav";
wav_hdr wavHeader;
FILE* openFile() {
const char* filePath;
FILE *wavFile;
headerSize = sizeof(wav_hdr);
filePath = path.c_str();
wavFile = fopen(filePath, "rb");
if (wavFile == NULL) {
printf("Error\n");
}
fread(&wavHeader, headerSize, 1, wavFile);
return wavFile;
}
int8_t MuLaw_Encode(int16_t number)
{
const uint16_t MULAW_MAX = 0x1FFF;
const uint16_t MULAW_BIAS = 33;
uint16_t mask = 0x1000;
uint8_t sign = 0;
uint8_t position = 12;
uint8_t lsb = 0;
if (number < 0)
{
number = -number;
sign = 0x80;
}
number += MULAW_BIAS;
if (number > MULAW_MAX)
{
number = MULAW_MAX;
}
for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--)
;
lsb = (number >> (position - 4)) & 0x0f;
return (~(sign | ((position - 5) << 4) | lsb));
}
int fileSize(FILE *file) {
int fileSize = 0;
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
return fileSize;
}
double bitsPerSample() {
double bitsPerE;
bitsPerE = wavHeader.bitsPerSample;
return bitsPerE;
}
int main() {
FILE *wavFile;
wavFile = openFile();
FILE* fptr2;
fptr2 = fopen("file2.wav", "wb");
int samples_count = fileSize(wavFile) / bitsPerSample();
short int *value = new short int[samples_count];
for (int16_t i = 0; i < samples_count; i++)
{
fread(&value[i], samples_count, 1, wavFile);
cout << value[i] << " "; // the output is in the attached picture
MuLaw_Encode(value[i]);
}
fwrite(value, sizeof(char), samples_count, fptr2);
return 0;
}
I took the u-law algorithm from here (2.1. µ-Law Compression (Encoding) Algorithm)
Am I doing something wrong? Because I obtain a corrupt file.
No header is ever written to the result file, so the first part of the data would get interpreted as a header, and it would be wrong. You can see in the file that it does not start with RIFFþR�WAVEfmt or something sufficiently similar.
The data written to the result file is value, the original data read from the input file, not the µ-law encoded data (which is only cout'ed and not saved).
The loop that reads the samples reads some wrong samples, because the computation of samples_count puts the current position back at the start, where the header is.

Read a binary (exe,zip etc..) file into a char*, c++

I'm trying to read a file and put bytes in a byte buffer, but when i try to read exe or zip file not all bytes are loaded in the buffer. my function:
char* read_file_bytes(const string &name) {
FILE *img = fopen(name.c_str(), "rb");
fseek(img, 0, SEEK_END);
unsigned long filesize = ftell(img);
char *buffer = (char*)malloc(sizeof(char)*filesize);
rewind(img);
fread(buffer, sizeof(char), filesize, img);
return buffer;
}
the piece of code that check the buffer:
char* bytes = read_file_bytes(path);
for(int i = 0; i < strlen(bytes); i++)
cout << hex << (unsigned int)(bytes[i]);
strlen() is designed for text characters, not for binary bytes. It stops counting when it encounters a nul char (0x00), which binary data is likely to contain.
Your read_file_bytes() function knows how many bytes it reads in. You need to return that number to the caller, eg:
typedef unsigned char byte;
byte* read_file_bytes(const std::string &name, unsigned long &filesize)
{
filesize = 0;
FILE *img = fopen(name.c_str(), "rb");
if (!img)
return NULL;
if (fseek(img, 0, SEEK_END) != 0)
{
fclose(img);
return NULL;
}
long size = ftell(img);
if (size == -1L)
{
fclose(img);
return NULL;
}
byte *buffer = static_cast<byte*>(std::malloc(size));
if (!buffer)
{
fclose(img);
return NULL;
}
rewind(img);
if (fread(buffer, 1, size, img) < size)
{
free(buffer);
close(img);
return NULL;
}
fclose(img);
filesize = size;
return buffer;
}
unsigned long filesize;
byte* bytes = read_file_bytes(path, filesize);
for(unsigned long i = 0; i < filesize; ++i)
std::cout << std::hex << static_cast<unsigned int>(bytes[i]);
free(bytes);
Note that this approach is very C-ish and error prone. A more C++ approach would look like this instead:
using byte = unsigned char;
// or, use std::byte in C++17 and later...
std::vector<byte> read_file_bytes(const std::string &name)
{
std::ifstream img;
img.exceptions(std::ifstream::failbit | std::ifstream::badbit);
img.open(name.c_str(), std::ifstream::binary | std::ifstream::ate);
std::ifstream::pos_type size = img.tellg();
ifs.seekg(0, std::ios::beg);
// or, use std::filesystem::file_size() instead...
std::vector<byte> buffer(size);
img.read(buffer.data(), size);
return buffer;
}
std::vector<byte> bytes = read_file_bytes(path);
for(byte b : bytes)
std::cout << std::hex << static_cast<unsigned int>(b);

extract raw image data but result is out of expect

I am using C++ to extract the raw image data.
But here comes a trouble.
I use either fseek or fread functions to move the file pointer, but both results are out of my expectation.
It seems the pointer is not the location which I want to move to.
Could someone give me a hint?
#include <stdio.h>
#include <stdlib.h>
int IMAGE_WIDTH=1280;
int IMAGE_HEIGHT=800;
int size=1280*800*2;
int header=128;
int line_padding=0;
int main()
{
FILE* fd;
FILE* fd_bin;
char *temp = (char*)malloc(size);
char *dat = (char*)malloc(size);
if (!dat) {
perror("malloc");
return NULL;
}
fd = fopen("original.raw", "rb");
if (!fd) {
printf("File Read Fail...\n");
exit(1);
}
// fseek(fd, header, SEEK_SET);
fread(temp, 1, header, fd);
for(int k=0;k<IMAGE_HEIGHT;k++)
{
fread(dat, 1, IMAGE_WIDTH*2, fd);
//fseek(fd , line_padding*2, SEEK_CUR);
fread(temp, 1, line_padding*2, fd);
}
/////////////////////////////Save bin
fd_bin = fopen("output.raw", "wb");
if (!fd_bin) {
printf("File Open Fail...\n");
exit(1);
}
fwrite( dat, 1, IMAGE_WIDTH*IMAGE_HEIGHT*2, fd_bin);
fclose(fd_bin);
///////////////////////////////////////////
fclose(fd);
free(temp);
free(dat);
}

How to decode one AAC frame at a time using C++?

I want to decode a stream of AAC frames continuously, one frame at a time.
I went through the ffmpeg examples (The correct answer doesn't need to make use of ffmpeg necessarily), and I only found examples using complete AAC files and batch algorithms. But I want to decode a continuous AAC stream. How can I do this?
UPDATE: Following the comments and Decode AAC to PCM with ffmpeg on android , I was able to decode to PCM using ffmpeg, however the output is very metallic and noisy. What am I doing wrong here when calling this method for each AAC frame:
...
/*loop that receives frame in buffer*/
while(1){
/*receive frame*/
input = receive_one_buffer();
/*decode frame*/
decodeBuffer(input,strlen(input),Outfile);
}
...
/*decode frame*/
void decodeBuffer(char * input, int numBytes, ofstream& Outfile) {
/*"input" contains one AAC-LC frame*/
//copy bytes from buffer
uint8_t inputBytes[numBytes + FF_INPUT_BUFFER_PADDING_SIZE];
memset(inputBytes, 0, numBytes + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(inputBytes, input, numBytes);
av_register_all();
AVCodec *codec = avcodec_find_decoder(CODEC_ID_AAC);
AVCodecContext *avCtx = avcodec_alloc_context();
avCtx->channels = 1;
avCtx->sample_rate = 44100;
//the input buffer
AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.size = numBytes; //input buffer size
avPacket.data = inputBytes; // the input buffer
int outSize;
int len;
uint8_t *outbuf = static_cast<uint8_t *>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE));
while (avPacket.size > 0) {
outSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(avCtx, (short *) outbuf, &outSize,
&avPacket);
Outfile.write((char*)outbuf, outSize);
avPacket.size -= len;
avPacket.data += len;
}
av_free_packet(&avPacket);
avcodec_close(avCtx);
//av_free(avCtx);
return;
}
You have to keep the decoder alive between subsequent decode calls.
The AAC decoder must decode the previous buffer to be correctly "primed".
Please check for details:
https://developer.apple.com/library/mac/technotes/tn2258/_index.html
The following code assumes that the "ReceiveBuffer" function returns exactly one
complete AAC access unit.
(BTW: you can't use strlen on a binary buffer; you'll get the distance to the first zero and not the buffer length)
#include <iostream>
#include <fstream>
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libavdevice\avdevice.h"
#include "libavfilter\avfilter.h"
AVCodecContext * CreateContext()
{
av_register_all();
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
AVCodecContext *avCtx = avcodec_alloc_context3(codec);
return avCtx;
}
int32_t DecodeBuffer
(
std::ostream & output,
uint8_t * pInput,
uint32_t cbInputSize,
AVCodecContext * pAVContext
)
{
int32_t cbDecoded = 0;
//the input buffer
AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.size = cbInputSize; //input buffer size
avPacket.data = pInput; // the input bufferra
AVFrame * pDecodedFrame = av_frame_alloc();
int nGotFrame = 0;
cbDecoded = avcodec_decode_audio4( pAVContext,
pDecodedFrame,
& nGotFrame,
& avPacket);
int data_size = av_samples_get_buffer_size( NULL,
pAVContext->channels,
pDecodedFrame->nb_samples,
pAVContext->sample_fmt,
1);
output.write((const char*)pDecodedFrame->data[0],data_size);
av_frame_free(&pDecodedFrame);
return cbDecoded;
}
uint8_t * ReceiveBuffer( uint32_t * cbBufferSize)
{
// TODO implement
return NULL;
}
int main
(
int argc,
char *argv[]
)
{
int nResult = 0;
AVCodecContext * pAVContext = CreateContext();
std::ofstream myOutputFile("audio.pcm",std::ios::binary);
while(1)
{
uint32_t cbBufferSize = 0;
uint8_t *pCompressedAudio = ReceiveBuffer( &cbBufferSize);
if(cbBufferSize && pCompressedAudio)
{
DecodeBuffer( myOutputFile,
pCompressedAudio,
cbBufferSize,
pAVContext);
}
else
{
break;
}
}
avcodec_close(pAVContext);
av_free(pAVContext);
return nResult;
}

using libvo-aacenc with libav in C++ program

I'm making a program that records and encodes this recording to aac.I made a function for linux and libfaac that does this job. Now I need to make this program for windows.I know i need to use libvo-aacenc and i don't know what to change in my code.Could you tell me what should I do? Here's my code.
static void encodeAac( const char *infilename,const char *filename)
{
AVCodec *codec;
AVCodecContext *c = NULL;
int frame_size, i, j, out_size, outbuf_size;
FILE *f,*fin;
SAMPLE *samples;
float t, tincr;
uint8_t *outbuf;
avcodec_register_all(); //Load all codecs
av_register_all();
codec = avcodec_find_encoder(AV_CODEC_ID_AAC); //Search for AAC codec
if (!codec) {
error("Codec not found");
}
c = avcodec_alloc_context();
c->bit_rate = 64000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->sample_rate = SAMPLE_RATE;
c->channels = NUM_CHANNELS;
c->time_base.num= 1;
c->time_base.den= SAMPLE_RATE;
c->profile= FF_PROFILE_AAC_MAIN;
if (avcodec_open(c, codec) < 0) {
error(add("","",avcodec_open(c, codec)).c_str());
exit(1);
}
f = fopen(filename, "wb");
fin=fopen(infilename,"rb");
if (!fin) {
error("could not open temporary file");
}
if (!f) {
error("could not open output file");
}
std::cout << c->frame_size*c->channels << std::endl;
samples = new SAMPLE[c->frame_size*c->channels];
outbuf = new uint8_t[FRAMES_PER_BUFFER * NUM_CHANNELS];
while(fread(samples,sizeof(SAMPLE),c->frame_size*c->channels,fin)){
out_size=avcodec_encode_audio(c,outbuf,FRAMES_PER_BUFFER * NUM_CHANNELS,samples);
fwrite(outbuf,sizeof(uint8_t),out_size,f);
}
for(int i=1;i<=4;i++){ //For buffer flushing
out_size=avcodec_encode_audio(c,outbuf,FRAMES_PER_BUFFER * NUM_CHANNELS,NULL);
fwrite(outbuf,sizeof(uint8_t),out_size,f);
}
fclose(f);
delete outbuf;
delete samples;
avcodec_close(c);
av_free(c);
}