shithub: aacdec

ref: 6a37599b964a61cf7a06f8a6a5a76ff4af4326dd
dir: /plugins/foo_mp4/packet_decoder_aac.cpp/

View raw version
#include "foobar2000/SDK/foobar2000.h"
#include <faad.h>


class packet_decoder_aac : public packet_decoder
{
    faacDecHandle hDecoder;
    faacDecFrameInfo frameInfo;
	void cleanup()
	{
		if (hDecoder) {faacDecClose(hDecoder);hDecoder=0;}
	}
public:
	packet_decoder_aac()
	{
		hDecoder = 0;
	}

	~packet_decoder_aac()
	{
		cleanup();
	}
	
	virtual bool is_our_type(const char * name) {return !stricmp_utf8(name,"AAC");}
	
	virtual unsigned get_max_frame_dependency() {return 1;}
	
	virtual bool init(const void * data,unsigned bytes,file_info * info)
	{
		if (hDecoder) faacDecClose(hDecoder);
		if (data==0) return false;
		hDecoder = faacDecOpen();
		if (hDecoder == 0)
		{
			cleanup();
			console::error("Failed to open FAAD2 library.");
			return false;
		}

		{
			faacDecConfigurationPtr config;
            config = faacDecGetCurrentConfiguration(hDecoder);
            config->outputFormat = 
#if audio_sample_size == 64
				FAAD_FMT_DOUBLE
#else
				FAAD_FMT_FLOAT
#endif
				;
            faacDecSetConfiguration(hDecoder, config);
		}

		unsigned long t_samplerate;
		unsigned char t_channels;

		if(faacDecInit2(hDecoder, (unsigned char*)data, bytes,
						&t_samplerate,&t_channels) < 0)
		{
			faacDecClose(hDecoder);
			hDecoder = 0;
			return false;
		}

		{
			mp4AudioSpecificConfig mp4ASC;
			if (AudioSpecificConfig((unsigned char*)data, bytes, &mp4ASC) >= 0)
			{
				static const char *ot[6] = { "NULL", "MAIN AAC", "LC AAC", "SSR AAC", "LTP AAC", "HE AAC" };
				info->info_set("aac_profile",ot[(mp4ASC.objectTypeIndex > 5)?0:mp4ASC.objectTypeIndex]);
			}
		}



		return true;


	}
	
	virtual void reset_after_seek()
	{
		if (hDecoder)
		{
			faacDecPostSeekReset(hDecoder, -1);
		}
	}

	virtual bool decode(const void * buffer,unsigned bytes,audio_chunk * out)
	{
		const audio_sample * sample_buffer = (const audio_sample*)faacDecDecode(hDecoder, &frameInfo, (unsigned char*)buffer, bytes);

		if (frameInfo.error > 0)
		{
			cleanup();
			console::error(faacDecGetErrorMessage(frameInfo.error));
			return false;
		}

		if (frameInfo.channels<=0)
		{
			cleanup();
			console::error("Internal decoder error.");
			return false;
		}

		if (frameInfo.samples)
		{
			return out->set_data(sample_buffer,frameInfo.samples / frameInfo.channels,frameInfo.channels,frameInfo.samplerate);
		}
		else
		{
			out->reset();
			return true;
		}
	}
	virtual const char * get_name() {return "MPEG-4 AAC";}
};

static packet_decoder_factory<packet_decoder_aac> AHAHAHAHA;


bool is_valid_aac_decoder_config(const void * data,unsigned bytes)
{
	mp4AudioSpecificConfig mp4ASC;
	return AudioSpecificConfig((unsigned char*)data, bytes, &mp4ASC)>=0;
}