All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.jaad.aac.DecoderConfig Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
package net.sourceforge.jaad.aac;

import static net.sourceforge.jaad.aac.Profile.*;

import net.sourceforge.jaad.aac.syntax.BitStream;
import net.sourceforge.jaad.aac.syntax.SyntaxConstants;
import net.sourceforge.jaad.aac.syntax.IBitStream;
import net.sourceforge.jaad.aac.syntax.PCE;

/**
 * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
 * under the Public Domain license. Code changes provided by the JCodec project
 * are distributed under FreeBSD license.
 * 
 * DecoderConfig that must be passed to the
 * Decoder constructor. Typically it is created via one of the
 * static parsing methods.
 *
 * @author in-somnia
 */
public class DecoderConfig implements SyntaxConstants {

	private Profile profile, extProfile;
	private SampleFrequency sampleFrequency;
	private ChannelConfiguration channelConfiguration;
	private boolean frameLengthFlag;
	private boolean dependsOnCoreCoder;
	private int coreCoderDelay;
	private boolean extensionFlag;
	//extension: SBR
	private boolean sbrPresent, downSampledSBR, sbrEnabled;
	//extension: error resilience
	private boolean sectionDataResilience, scalefactorResilience, spectralDataResilience;

	private DecoderConfig() {
		profile = Profile.AAC_MAIN;
		extProfile = Profile.UNKNOWN;
		sampleFrequency = SampleFrequency.SAMPLE_FREQUENCY_NONE;
		channelConfiguration = ChannelConfiguration.CHANNEL_CONFIG_UNSUPPORTED;
		frameLengthFlag = false;
		sbrPresent = false;
		downSampledSBR = false;
		sbrEnabled = true;
		sectionDataResilience = false;
		scalefactorResilience = false;
		spectralDataResilience = false;
	}

	/* ========== gets/sets ========== */
	public ChannelConfiguration getChannelConfiguration() {
		return channelConfiguration;
	}

	public void setChannelConfiguration(ChannelConfiguration channelConfiguration) {
		this.channelConfiguration = channelConfiguration;
	}

	public int getCoreCoderDelay() {
		return coreCoderDelay;
	}

	public void setCoreCoderDelay(int coreCoderDelay) {
		this.coreCoderDelay = coreCoderDelay;
	}

	public boolean isDependsOnCoreCoder() {
		return dependsOnCoreCoder;
	}

	public void setDependsOnCoreCoder(boolean dependsOnCoreCoder) {
		this.dependsOnCoreCoder = dependsOnCoreCoder;
	}

	public Profile getExtObjectType() {
		return extProfile;
	}

	public void setExtObjectType(Profile extObjectType) {
		this.extProfile = extObjectType;
	}

	public int getFrameLength() {
		return frameLengthFlag ? WINDOW_SMALL_LEN_LONG : WINDOW_LEN_LONG;
	}

	public boolean isSmallFrameUsed() {
		return frameLengthFlag;
	}

	public void setSmallFrameUsed(boolean shortFrame) {
		this.frameLengthFlag = shortFrame;
	}

	public Profile getProfile() {
		return profile;
	}

	public void setProfile(Profile profile) {
		this.profile = profile;
	}

	public SampleFrequency getSampleFrequency() {
		return sampleFrequency;
	}

	public void setSampleFrequency(SampleFrequency sampleFrequency) {
		this.sampleFrequency = sampleFrequency;
	}

	//=========== SBR =============
	public boolean isSBRPresent() {
		return sbrPresent;
	}

	public boolean isSBRDownSampled() {
		return downSampledSBR;
	}

	public boolean isSBREnabled() {
		return sbrEnabled;
	}

	public void setSBREnabled(boolean enabled) {
		sbrEnabled = enabled;
	}

	//=========== ER =============
	public boolean isScalefactorResilienceUsed() {
		return scalefactorResilience;
	}

	public boolean isSectionDataResilienceUsed() {
		return sectionDataResilience;
	}

	public boolean isSpectralDataResilienceUsed() {
		return spectralDataResilience;
	}

	/* ======== static builder ========= */
	/**
	 * Parses the input arrays as a DecoderSpecificInfo, as used in MP4
	 * containers.
	 * 
	 * @return a DecoderConfig
	 */
	public static DecoderConfig parseMP4DecoderSpecificInfo(byte[] data) throws AACException {
		final IBitStream _in = BitStream.createBitStream(data);
		final DecoderConfig config = new DecoderConfig();

		try {
			config.profile = readProfile(_in);

			int sf = _in.readBits(4);
			if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
			else config.sampleFrequency = SampleFrequency.forInt(sf);
			config.channelConfiguration = ChannelConfiguration.forInt(_in.readBits(4));

			Profile cp = config.profile;
			if (AAC_SBR == cp) {
                config.extProfile = cp;
                config.sbrPresent = true;
                sf = _in.readBits(4);
                //TODO: 24 bits already read; read again?
                //if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
                //if sample frequencies are the same: downsample SBR
                config.downSampledSBR = config.sampleFrequency.getIndex()==sf;
                config.sampleFrequency = SampleFrequency.forInt(sf);
                config.profile = readProfile(_in);
			} else if (AAC_MAIN == cp || AAC_LC ==  cp || AAC_SSR == cp || AAC_LTP == cp || ER_AAC_LC == cp || ER_AAC_LTP == cp || ER_AAC_LD == cp ) {
                //ga-specific info:
                config.frameLengthFlag = _in.readBool();
                if(config.frameLengthFlag) throw new AACException("config uses 960-sample frames, not yet supported"); //TODO: are 960-frames working yet?
                config.dependsOnCoreCoder = _in.readBool();
                if(config.dependsOnCoreCoder) config.coreCoderDelay = _in.readBits(14);
                else config.coreCoderDelay = 0;
                config.extensionFlag = _in.readBool();

                if(config.extensionFlag) {
                    if(cp.isErrorResilientProfile()) {
                        config.sectionDataResilience = _in.readBool();
                        config.scalefactorResilience = _in.readBool();
                        config.spectralDataResilience = _in.readBool();
                    }
                    //extensionFlag3
                    _in.skipBit();
                }

                if(config.channelConfiguration==ChannelConfiguration.CHANNEL_CONFIG_NONE) {
                    //TODO: is this working correct? -> ISO 14496-3 part 1: 1.A.4.3
                    _in.skipBits(3); //PCE
                    PCE pce = new PCE();
                    pce.decode(_in);
                    config.profile = pce.getProfile();
                    config.sampleFrequency = pce.getSampleFrequency();
                    config.channelConfiguration = ChannelConfiguration.forInt(pce.getChannelCount());
                }

                if(_in.getBitsLeft()>10) readSyncExtension(_in, config);
			} else {
                throw new AACException("profile not supported: "+cp.getIndex());
			}
			return config;
		}
		finally {
			_in.destroy();
		}
	}

	private static Profile readProfile(IBitStream _in) throws AACException {
		int i = _in.readBits(5);
		if(i==31) i = 32+_in.readBits(6);
		return Profile.forInt(i);
	}

	private static void readSyncExtension(IBitStream _in, DecoderConfig config) throws AACException {
		final int type = _in.readBits(11);
		switch(type) {
			case 0x2B7:
				final Profile profile = Profile.forInt(_in.readBits(5));

				if(profile.equals(Profile.AAC_SBR)) {
					config.sbrPresent = _in.readBool();
					if(config.sbrPresent) {
						config.profile = profile;

						int tmp = _in.readBits(4);

						if(tmp==config.sampleFrequency.getIndex()) config.downSampledSBR = true;
						if(tmp==15) {
							throw new AACException("sample rate specified explicitly, not supported yet!");
							//tmp = _in.readBits(24);
						}
					}
				}
				break;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy