Package org.kc7bfi.jflac.frame

Source Code of org.kc7bfi.jflac.frame.Header

package org.kc7bfi.jflac.frame;

/**
* libFLAC - Free Lossless Audio Codec library Copyright (C) 2001,2002,2003 Josh
* Coalson
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Library General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
* details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.io.IOException;

import org.kc7bfi.jflac.Constants;
import org.kc7bfi.jflac.io.BitInputStream;
import org.kc7bfi.jflac.metadata.StreamInfo;
import org.kc7bfi.jflac.util.ByteData;
import org.kc7bfi.jflac.util.CRC8;

/**
* Frame header class.
*
* @author kc7bfi
*/
public class Header {

    /**
     * The number of samples per subframe.
     */
    public int blockSize;
    /**
     * The sample rate in Hz.
     */
    public int sampleRate;
    /**
     * The number of channels (== number of subframes).
     */
    public int channels;
    /**
     * The channel assignment for the frame.
     */
    public int channelAssignment;
    /**
     * The sample resolution.
     */
    public int bitsPerSample;
    /**
     * The frame number or sample number of first sample in frame. use the
     * number_type value to determine which to use.
     */
    public int frameNumber = -1;
    /**
     * The sample number for the first sample in the frame.
     */
    public long sampleNumber = -1;
    /**
     * CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0). of the
     * raw frame header bytes, meaning everything before the CRC byte including
     * the sync code.
     */
    protected byte crc;

    /**
     * The constructor.
     *
     * @param is The InputBitStream
     * @param headerWarmup The header warm-up bytes
     * @param streamInfo The FLAC Stream Info
     * @throws IOException Thrown on error reading InputBitStream
     * @throws BadHeaderException Thrown if header is bad
     */
    public Header(BitInputStream is, byte[] headerWarmup, StreamInfo streamInfo) throws IOException, BadHeaderException {
        int blocksizeHint = 0;
        int sampleRateHint = 0;
        ByteData rawHeader = new ByteData(16); // MAGIC NUMBER based on the maximum frame header size, including CRC
        boolean isKnownVariableBlockSizeStream = ( streamInfo != null && streamInfo.getMinBlockSize() != streamInfo.getMaxBlockSize() );
        boolean isKnownFixedBlockSizeStream = ( streamInfo != null && streamInfo.getMinBlockSize() == streamInfo.getMaxBlockSize() );

        // init the raw header with the saved bits from synchronization
        rawHeader.append(headerWarmup[0]);
        rawHeader.append(headerWarmup[1]);

        // check to make sure that the reserved bits are 0
        if (( rawHeader.getData(1) & 0x03 ) != 0) { // MAGIC NUMBER
            throw new BadHeaderException("Bad Magic Number: " + ( rawHeader.getData(1) & 0xff ));
        }

        // Note that along the way as we read the header, we look for a sync
        // code inside.  If we find one it would indicate that our original
        // sync was bad since there cannot be a sync code in a valid header.

        // read in the raw header as bytes so we can CRC it, and parse it on the way
        for (int i = 0; i < 2; i++) {
            if (is.peekRawUInt(8) == 0xff) { // MAGIC NUMBER for the first 8 frame sync bits
                throw new BadHeaderException("Found sync byte");
            }
            rawHeader.append((byte) is.readRawUInt(8));
        }

        int bsType = ( rawHeader.getData(2) >> 4 ) & 0x0f;
        switch (bsType) {
            case 0:
                if (!isKnownFixedBlockSizeStream) {
                    throw new BadHeaderException("Unknown Block Size (0)");
                }
                blockSize = streamInfo.getMinBlockSize();
                break;
            case 1:
                blockSize = 192;
                break;
            case 2:
            case 3:
            case 4:
            case 5:
                blockSize = 576 << ( bsType - 2 );
                break;
            case 6:
            case 7:
                blocksizeHint = bsType;
                break;
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
            case 15:
                blockSize = 256 << ( bsType - 8 );
                break;
            default:
                break;
        }
        //System.out.println("BSType="+bsType+" BS="+blockSize);

        int srType = rawHeader.getData(2) & 0x0f;
        switch (srType) {
            case 0:
                if (streamInfo == null) {
                    throw new BadHeaderException("Bad Sample Rate (0)");
                }
                sampleRate = streamInfo.getSampleRate();
                break;
            case 1:
            case 2:
            case 3:
                throw new BadHeaderException("Bad Sample Rate (" + srType + ")");
            case 4:
                sampleRate = 8000;
                break;
            case 5:
                sampleRate = 16000;
                break;
            case 6:
                sampleRate = 22050;
                break;
            case 7:
                sampleRate = 24000;
                break;
            case 8:
                sampleRate = 32000;
                break;
            case 9:
                sampleRate = 44100;
                break;
            case 10:
                sampleRate = 48000;
                break;
            case 11:
                sampleRate = 96000;
                break;
            case 12:
            case 13:
            case 14:
                sampleRateHint = srType;
                break;
            case 15:
                throw new BadHeaderException("Bad Sample Rate (" + srType + ")");
            default:
        }

        int asgnType = (int) ( ( rawHeader.getData(3) >> 4 ) & 0x0f );
        //System.out.println("AsgnType="+asgnType+" "+(rawHeader.space[3] >> 4));
        if (( asgnType & 8 ) != 0) {
            channels = 2;
            switch (asgnType & 7) {
                case 0:
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_LEFT_SIDE;
                    break;
                case 1:
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_RIGHT_SIDE;
                    break;
                case 2:
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_MID_SIDE;
                    break;
                default:
                    throw new BadHeaderException("Bad Channel Assignment (" + asgnType + ")");
            }
        } else {
            channels = (int) asgnType + 1;
            channelAssignment = Constants.CHANNEL_ASSIGNMENT_INDEPENDENT;
        }

        int bpsType = (int) ( rawHeader.getData(3) & 0x0e ) >> 1;
        switch (bpsType) {
            case 0:
                if (streamInfo != null) {
                    bitsPerSample = streamInfo.getBitsPerSample();
                } else {
                    throw new BadHeaderException("Bad BPS (" + bpsType + ")");
                }
                break;
            case 1:
                bitsPerSample = 8;
                break;
            case 2:
                bitsPerSample = 12;
                break;
            case 4:
                bitsPerSample = 16;
                break;
            case 5:
                bitsPerSample = 20;
                break;
            case 6:
                bitsPerSample = 24;
                break;
            case 3:
            case 7:
                throw new BadHeaderException("Bad BPS (" + bpsType + ")");
            default:
                break;
        }

        if (( rawHeader.getData(3) & 0x01 ) != 0) { // this should be a zero padding bit
            throw new BadHeaderException("this should be a zero padding bit");
        }

        if (( blocksizeHint != 0 ) && isKnownVariableBlockSizeStream) {
            sampleNumber = is.readUTF8Long(rawHeader);
            if (sampleNumber == 0xffffffffffffffffL) { // i.e. non-UTF8 code...
                throw new BadHeaderException("Bad Sample Number");
            }
        } else {
            int lastFrameNumber = is.readUTF8Int(rawHeader);
            if (lastFrameNumber == 0xffffffff) { // i.e. non-UTF8 code...
                throw new BadHeaderException("Bad Last Frame");
            }
            sampleNumber = (long) streamInfo.getMinBlockSize() * (long) lastFrameNumber;
        }

        if (blocksizeHint != 0) {
            int blockSizeCode = is.readRawUInt(8);
            rawHeader.append((byte) blockSizeCode);
            if (blocksizeHint == 7) {
                int blockSizeCode2 = is.readRawUInt(8);
                rawHeader.append((byte) blockSizeCode2);
                blockSizeCode = ( blockSizeCode << 8 ) | blockSizeCode2;
            }
            blockSize = blockSizeCode + 1;
        }

        if (sampleRateHint != 0) {
            int sampleRateCode = is.readRawUInt(8);
            rawHeader.append((byte) sampleRateCode);
            if (sampleRateHint != 12) {
                int sampleRateCode2 = is.readRawUInt(8);
                rawHeader.append((byte) sampleRateCode2);
                sampleRateCode = ( sampleRateCode << 8 ) | sampleRateCode2;
            }
            if (sampleRateHint == 12) {
                sampleRate = sampleRateCode * 1000;
            } else if (sampleRateHint == 13) {
                sampleRate = sampleRateCode;
            } else {
                sampleRate = sampleRateCode * 10;
            }
        }

        // read the CRC-8 byte
        byte crc8 = (byte) is.readRawUInt(8);

        if (CRC8.calc(rawHeader.getData(), rawHeader.getLen()) != crc8) {
            throw new BadHeaderException("STREAM_DECODER_ERROR_STATUS_BAD_HEADER");
        }
    }

    /**
     * Return a descriptive string for this object.
     *
     * @return the string description
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return "FrameHeader:"
                + " BlockSize=" + blockSize
                + " SampleRate=" + sampleRate
                + " Channels=" + channels
                + " ChannelAssignment=" + channelAssignment
                + " BPS=" + bitsPerSample
                + " SampleNumber=" + sampleNumber;
    }
}
TOP

Related Classes of org.kc7bfi.jflac.frame.Header

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.