-
-
Save cprakashagr/550b65808590255eb529 to your computer and use it in GitHub Desktop.
C++ ffmpeg decoder
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
/* | |
* encoder.cpp | |
* | |
* Created on: Jul 12, 2012 | |
* Author : Abhishek Hingnikar | |
* @TODO: remove the file deps. | |
* ADD STREAM DEPS so that u can buffer output. | |
* Structure | |
* @JSAPI | |
* ffmpeg{ | |
* decoder:Constructor | |
* (codec,required_specs{ | |
* Sample_Rate, | |
* etc. | |
* }){ | |
* decode:(buffer toDecode,CallBack AfterDecode); | |
* decodeSync( buffer toDecode); | |
* | |
* }; | |
* | |
* encoder:Constructor | |
* (codec) | |
* { | |
* encode( buffer ToEncode , CallBack AfterEncode ); | |
* encodeSync ( buffer toEncode ) | |
* } | |
* | |
* } | |
* | |
*/ | |
#include<iostream> | |
#include<vector> | |
#define __STDC_CONSTANT_MACROS | |
#ifndef INT64_C | |
#define INT64_C(c) (c ## LL) | |
#define UINT64_C(c) (c ## ULL) | |
#endif | |
# include <stdint.h> | |
# include <inttypes.h> | |
extern"C"{ | |
#include "libavutil/imgutils.h" | |
#include"libavcodec/avcodec.h" | |
#include"libavformat/avformat.h" | |
#include"libavutil/error.h" | |
#include"libavutil/mathematics.h" | |
#include "libavutil/samplefmt.h" | |
} | |
#define INBUF_SIZE 4096 | |
#define AUDIO_INBUF_SIZE 20480 | |
#define AUDIO_REFILL_THRESH 4096 | |
using namespace std; | |
class ffDecFile{ | |
private: | |
AVCodec *codec; | |
AVCodecContext *c; | |
int len; | |
vector<uint8_t> inBuf; | |
AVPacket * avpkt; | |
FILE *f; | |
int finished; | |
AVFrame *decoded_frame; | |
void cleanup(){ | |
if(this->c){ | |
avcodec_close(this->c); | |
av_free(this->c); | |
av_free(this->decoded_frame); | |
} | |
if(this->f){ | |
fclose(this->f); | |
} | |
} | |
int decode(){ | |
/* Decode a part */ | |
if( this->avpkt->size > 0 ){ | |
int got_packet = 0; | |
if(!this->decoded_frame){ | |
if(!(this->decoded_frame = avcodec_alloc_frame())){ | |
cout<<"\n Failed to allocate memory ... Add more ram add more ram!"; | |
return -4; | |
} | |
}else | |
avcodec_get_frame_defaults(this->decoded_frame); | |
this->len = avcodec_decode_audio4(this->c,this->decoded_frame,&got_packet,this->avpkt); | |
if(this->len < 0 ){ | |
cout<<"\n Error Reading packet"; | |
return -2; | |
} | |
this->avpkt->size -= len; | |
this->avpkt->data += len; | |
this->avpkt->pts = this->avpkt->dts = AV_NOPTS_VALUE; | |
/* Prepare for net routine */ | |
if(this->avpkt->size < AUDIO_REFILL_THRESH){ | |
memmove(this->inBuf.data(),this->avpkt->data,this->avpkt->size); | |
this->avpkt->data = this->inBuf.data(); | |
this->len = fread(this->avpkt->data+this->avpkt->size,1,AUDIO_INBUF_SIZE - this->avpkt->size,f); | |
if( this->len > 0){ | |
this->avpkt->size += len; | |
} | |
} | |
return 0; | |
} | |
return 1; // If finished. | |
} | |
public: | |
int init(char *file,CodecID codec_enum){ | |
/* Initialize defs */ | |
this->finished = 0; | |
this->c = new AVCodecContext; | |
this->len = 0; | |
this->f = NULL; | |
this->avpkt = new AVPacket; | |
this->decoded_frame = new AVFrame; | |
this->inBuf.resize(AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
av_init_packet(this->avpkt); | |
this->codec = avcodec_find_decoder(codec_enum); | |
if(!this->codec){ | |
cout<<"\n Can't find the codec"; | |
this->cleanup(); | |
return -1; | |
} | |
this->c = avcodec_alloc_context3(this->codec); | |
if( avcodec_open2(this->c,this->codec,NULL)< 0) | |
{ | |
cout<<"\n Error opening codec"; | |
this->cleanup(); | |
return -2; | |
}; | |
f = fopen(file,"rb"); | |
if(!f){ | |
cout<<"\n Error opening file"; | |
this->cleanup(); | |
return -3; | |
} | |
/* Initial read */ | |
this->avpkt->size = fread(this->inBuf.data(),1,AUDIO_INBUF_SIZE,f); | |
this->avpkt->data = inBuf.data(); | |
return 0; | |
} | |
AVCodecContext * getContext(){ | |
return this->c; | |
} | |
AVFrame * getDecodedFrame(){ | |
int state = this->decode(); | |
if(!finished) | |
if( state == 1 || state == 0){ | |
if(state) | |
this->finished = 1; | |
return (this->decoded_frame); | |
}else{ | |
this->cleanup(); | |
} | |
return NULL; | |
} | |
}; | |
struct codecData{ | |
int bitRate; | |
int sampleRate; | |
int channels; | |
enum AVSampleFormat sample_fmt; | |
}; | |
class ffEnc{ | |
AVCodec *codec; | |
AVCodecContext *c= NULL; | |
AVFrame * frame; | |
AVPacket * encoded_packet; | |
int frame_size, i, j, out_size; | |
void cleanup(){ | |
if(this->c){ | |
avcodec_close(this->c); | |
av_free(this->c); | |
} | |
} | |
/* | |
* Private function that actually encodes and returns the stuff. | |
*/ | |
int encode(){ | |
int got_packet = 0; | |
this->out_size = avcodec_encode_audio2(this->c,this->encoded_packet,this->frame,&got_packet); | |
if( out_size < 0 ){ | |
return -2; // known error in this case. Will be logged by Libavcodec.. hopefully wont mess with node.js | |
} | |
if( got_packet < 0 ){ | |
cout<<"Contact a Plumber!!!! \n we have got a leakage , and its unknown!!"; | |
return -4; // Unknown leakage get ur seals ready to fix this . | |
} | |
// Success | |
return 0; | |
} | |
public: | |
/* | |
* @Public Api | |
* Constructor for the encoder class | |
* and binding source for the node.js | |
* though node.js will use different parameters | |
* TODO: Change the parameters to v8 based JS objects that come from JavaScript. | |
*/ | |
int init(char* fileName,CodecID codec_id,codecData defs){ | |
this->codec = new AVCodec; | |
this->frame = new AVFrame; | |
this->encoded_packet = new AVPacket; | |
this->encoded_packet->data = NULL; | |
this->codec = avcodec_find_encoder(codec_id); | |
if(!codec){ | |
cout<<"Error opening codec"; | |
this->cleanup(); | |
return -1; | |
} | |
this->c = avcodec_alloc_context3(this->codec); | |
this->c->sample_fmt = defs.sample_fmt; | |
this->c->bit_rate = defs.bitRate; | |
this->c->channels = defs.channels; | |
this->c->sample_rate= defs.sampleRate; | |
/* Open the encoder */ | |
if( avcodec_open2(this->c,this->codec,NULL)< 0){ | |
cout<<"Error opening the codec"; | |
this->cleanup(); | |
return -2; | |
} | |
this->frame_size = this->c->frame_size; | |
// Success. | |
return 0; | |
} | |
/* | |
* @Public API for encoding and also to be binded to node.js | |
*/ | |
AVPacket * getEncodedPacket( AVFrame * toEncode){ | |
// toEncode is the frame to encode . in node.js this will be ported to buffer to encode. | |
this->frame = toEncode; | |
int state = this->encode(); | |
if(state != 0){ | |
return NULL; | |
}else{ | |
return this->encoded_packet; | |
} | |
} | |
}; | |
int main(){ | |
av_register_all(); | |
ffDecFile* ffmpegd = new ffDecFile() ; | |
ffEnc * ffmpege = new ffEnc(); | |
FILE * outFile; | |
AVPacket * out_pack = new AVPacket; | |
outFile = fopen("ghoo.mp3","wb+"); | |
cout<<"\n Worked"; | |
if(ffmpegd->init("buu.mp3",CODEC_ID_MP3)==0){ | |
cout<<"\n File loaded"; | |
} | |
codecData defs; | |
AVFrame * outFrame = NULL; | |
outFrame = ffmpegd->getDecodedFrame(); | |
if(outFrame){ | |
AVCodecContext * dec_con = ffmpegd->getContext(); | |
defs.sample_fmt = dec_con->sample_fmt;// Findout whats our decoder is speaking | |
defs.channels = dec_con->channels; // now start making our encoder speak the same | |
defs.sampleRate = dec_con->sample_rate; // and bing we are good to go. | |
defs.bitRate = 64000; | |
ffmpege->init("ghoo.mp3",CODEC_ID_MP3,defs); | |
out_pack = ffmpege->getEncodedPacket(outFrame); | |
if(out_pack != NULL) | |
fwrite(out_pack->data, 1, out_pack->size, outFile); | |
else{ | |
fclose(outFile); | |
cout<<"No encoded frame , Call Plumber this is a major leak!"; | |
return -2; | |
} | |
}else{ | |
cout<<"\n Unknown error occurred please consult Dr.Debugger."; | |
return -1; | |
} | |
float * samples = NULL; | |
long int total_samp = 0; | |
while(outFrame != NULL){ | |
/* Do some cool stuff with data */ | |
outFrame = ffmpegd->getDecodedFrame(); | |
out_pack = ffmpege->getEncodedPacket(outFrame); | |
if(out_pack != NULL) | |
fwrite(out_pack->data, 1, out_pack->size, outFile); | |
else{ | |
fclose(outFile); | |
cout<<"No encoded frame , Call Plumber this is a major leak!"; | |
return -2; | |
} | |
} | |
cout<<"\n Finished Reading file"; | |
cout<<"\n File writing complete"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment