⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oggpageheader.java

📁 YOYOPlayer MP3播放器 java+JMF实现
💻 JAVA
字号:
/*
 * Entagged Audio Tag library
 * Copyright (c) 2003-2005 Rapha�l Slinckx <raphael@slinckx.net>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.hadeslee.audiotag.audio.ogg.util;

import com.hadeslee.audiotag.audio.exceptions.CannotReadException;
import com.hadeslee.audiotag.audio.generic.Utils;

import java.io.RandomAccessFile;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;


/**
 * $Id: OggPageHeader.java,v 1.11 2007/10/11 21:36:08 paultaylor Exp $
 *
 * reference:http://xiph.org/ogg/doc/framing.html
 *
 * @author Raphael Slinckx (KiKiDonK)
 * @version 16 d�cembre 2003
 */
public class OggPageHeader
{
    // Logger Object
       public static Logger logger = Logger.getLogger("com.hadeslee.jaudiotagger.audio.ogg.atom");

    //Capture pattern at start of header
    public static final byte[] CAPTURE_PATTERN = {'O', 'g', 'g','S'};

    //Ogg Page header is always 27 bytes plus the size of the segment table which is variable
    public static final int OGG_PAGE_HEADER_FIXED_LENGTH = 27;

    //Can have upto 255 segments in a page
    public static final int MAXIMUM_NO_OF_SEGMENT_SIZE = 255;

    //Each segmets can be upto 255 bytes
    public static final int MAXIMUM_SEGMENT_SIZE = 255;

    //Maximum size of pageheader (27 + 255 = 282)
    public static final int MAXIMUM_PAGE_HEADER_SIZE = OGG_PAGE_HEADER_FIXED_LENGTH + MAXIMUM_NO_OF_SEGMENT_SIZE;

    //Maximum size of page data following the page header (255 * 255 = 65025)
    public static final int MAXIMUM_PAGE_DATA_SIZE = MAXIMUM_NO_OF_SEGMENT_SIZE * MAXIMUM_SEGMENT_SIZE;

    //Maximum size of page includes header and data (282 + 65025 = 65307 bytes)
    public static final int MAXIMUM_PAGE_SIZE = MAXIMUM_PAGE_HEADER_SIZE + MAXIMUM_PAGE_DATA_SIZE;

    //Starting positions of the various attributes
    public static final int FIELD_CAPTURE_PATTERN_POS  = 0;
    public static final int FIELD_STREAM_STRUCTURE_VERSION_POS  = 4;
    public static final int FIELD_HEADER_TYPE_FLAG_POS  = 5;
    public static final int FIELD_ABSOLUTE_GRANULE_POS  = 6;
    public static final int FIELD_STREAM_SERIAL_NO_POS  = 14;
    public static final int FIELD_PAGE_SEQUENCE_NO_POS  = 18;
    public static final int FIELD_PAGE_CHECKSUM_POS     = 22;
    public static final int FIELD_PAGE_SEGMENTS_POS     = 26;
    public static final int FIELD_SEGMENT_TABLE_POS     = 27;

    //Length of various attributes
    public static final int FIELD_CAPTURE_PATTERN_LENGTH  = 4;
    public static final int FIELD_STREAM_STRUCTURE_VERSION_LENGTH  = 1;
    public static final int FIELD_HEADER_TYPE_FLAG_LENGTH  = 1;
    public static final int FIELD_ABSOLUTE_GRANULE_LENGTH  = 8;
    public static final int FIELD_STREAM_SERIAL_NO_LENGTH  = 4;
    public static final int FIELD_PAGE_SEQUENCE_NO_LENGTH  = 4;
    public static final int FIELD_PAGE_CHECKSUM_LENGTH     = 4;
    public static final int FIELD_PAGE_SEGMENTS_LENGTH     = 1;

    private byte[] rawHeaderData;
    private double absoluteGranulePosition;
    private int checksum;
    private byte headerTypeFlag;

    private boolean isValid = false;
    private int pageLength = 0;
    private int pageSequenceNumber, streamSerialNumber;
    private byte[] segmentTable;

    private List<PacketStartAndLength> packetList = new ArrayList<PacketStartAndLength>();
    private boolean lastPacketIncomplete = false;


    public static OggPageHeader read (RandomAccessFile raf) throws IOException,CannotReadException
    {
        long start = raf.getFilePointer();
        logger.info("Trying to read OggPage at:"+start);

        byte[] b = new byte[OggPageHeader.CAPTURE_PATTERN.length];
        raf.read(b);
        if (!(Arrays.equals(b, OggPageHeader.CAPTURE_PATTERN)))
        {
            throw new CannotReadException("OggS Header could not be found, not an ogg stream:"+new String(b));
        }

        raf.seek(start + OggPageHeader.FIELD_PAGE_SEGMENTS_POS);
        int pageSegments = raf.readByte() & 0xFF; //unsigned
        raf.seek(start);

        b = new byte[OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageSegments];
        raf.read(b);


        OggPageHeader pageHeader = new OggPageHeader(b);

        //Now just after PageHeader, ready for Packet Data
        return pageHeader;
    }

    public OggPageHeader(byte[] b)
    {
        this.rawHeaderData = b;
        int streamStructureRevision = b[FIELD_STREAM_STRUCTURE_VERSION_POS];
        headerTypeFlag = b[FIELD_HEADER_TYPE_FLAG_POS];
        if (streamStructureRevision == 0)
        {
            this.absoluteGranulePosition = 0;
            for (int i = 0; i < FIELD_ABSOLUTE_GRANULE_LENGTH; i++)
            {
                this.absoluteGranulePosition += u(b[i + FIELD_ABSOLUTE_GRANULE_POS]) * Math.pow(2, 8 * i);
            }

            streamSerialNumber = Utils.getNumberLittleEndian(b,FIELD_STREAM_SERIAL_NO_POS,17);
            pageSequenceNumber = Utils.getNumberLittleEndian(b,FIELD_PAGE_SEQUENCE_NO_POS,21);
            checksum =Utils.getNumberLittleEndian(b,FIELD_PAGE_CHECKSUM_POS,25);
            int pageSegments = u( b[FIELD_PAGE_SEGMENTS_POS  ] );

            this.segmentTable = new byte[b.length - OGG_PAGE_HEADER_FIXED_LENGTH];
            int packetLength        = 0;
            Integer segmentLength   = null;
            for (int i = 0; i < segmentTable.length; i++)
            {
                segmentTable[i] = b[OGG_PAGE_HEADER_FIXED_LENGTH + i];
                segmentLength = u(segmentTable[i]);
                this.pageLength += segmentLength;
                packetLength+=segmentLength;

                if(segmentLength<MAXIMUM_SEGMENT_SIZE)
                {
                    packetList.add(new PacketStartAndLength(pageLength-packetLength,packetLength));
                    packetLength=0;
                }
            }

            //If last segment value is 255 this packet continues onto next page
            //and wont have been added to the packetStartAndEnd list yet
            if(segmentLength== MAXIMUM_SEGMENT_SIZE)
            {
                packetList.add(new PacketStartAndLength(pageLength-packetLength,packetLength));
                lastPacketIncomplete=true;
            }
            isValid = true;
        }

        logger.info("Constructed OggPage:"+this.toString());
    }

    private int u(int i)
    {
        return i & 0xFF;
    }

    /**
     *
     * @return true if the last packet on this page extends to the next page
     */
    public boolean isLastPacketIncomplete()
    {
        return lastPacketIncomplete;
    }

    public double getAbsoluteGranulePosition()
    {
        logger.fine("Number Of Samples: "+absoluteGranulePosition);
        return this.absoluteGranulePosition;
    }


    public int getCheckSum()
    {
        return checksum;
    }


    public byte getHeaderType()
    {
        return headerTypeFlag;
    }


    public int getPageLength()
    {
        logger.fine("This page length: "+pageLength);
        return this.pageLength;
    }

    public int getPageSequence()
    {
        return pageSequenceNumber;
    }

    public int getSerialNumber()
    {
        return streamSerialNumber;
    }

    public byte[] getSegmentTable()
    {
        return this.segmentTable;
    }

    public boolean isValid()
    {
        return isValid;
    }

    /**
     *
     * @return a list of packet start position and size within this page.
     */
    public List<PacketStartAndLength> getPacketList()
    {
        return packetList;
    }

    /**
     *
     * @return the raw header data that this pageheader is derived from
     */
    public byte[] getRawHeaderData()
    {
        return rawHeaderData;
    }

    public String toString()
    {
        String out = "Ogg Page Header:isvalid:"+isValid
            +":type:"+headerTypeFlag
            +":oggpageheaderlength:"+rawHeaderData.length
            +":length:"+pageLength
            +":seqno:"+getPageSequence()
            +":packetincomplete:"+isLastPacketIncomplete()
            +":sernum:"+this.getSerialNumber();

        for(PacketStartAndLength packet:getPacketList())
        {
            out+=packet.toString();
        }
        return out;
    }

    /**
     * Within the page specifies the start and length of each packet
     * in the page offset from the end of the pageheader (after the segment table)
     */
    public static class PacketStartAndLength
    {
        private Integer startPosition = 0;
        private Integer length   = 0;

        public PacketStartAndLength(int startPosition,int length)
        {
            this.startPosition=startPosition;
            this.length =length;
        }

        public int getStartPosition()
        {
            return startPosition;
        }

        public void setStartPosition(int startPosition)
        {
            this.startPosition = startPosition;
        }

        public int getLength()
        {
            return length;
        }

        public void setLength(int length)
        {
            this.length = length;
        }

        public String toString()
        {
            return "start:"+startPosition+":length:"+length;
        }
    }

    /** This represents all the flags that can be set in the headerType field.
     *  Note these values can be ORED together. For example the last packet in
     *  a file would normally have a value of 0x5 because both the CONTINUED_PACKET
     *  bit and the END_OF_BITSTREAM bit would be set.
     */
    public static enum HeaderTypeFlag
    {
        FRESH_PACKET((byte)0x0),
        CONTINUED_PACKET((byte)0x1),
        START_OF_BITSTREAM((byte)0x2),
        END_OF_BITSTREAM((byte)0x4);

        byte fileValue;
        HeaderTypeFlag(byte fileValue)
        {
            this.fileValue=fileValue;
        }

        /**
         *
         * @return the value that should be written to file to enable this flag
         */
        public byte getFileValue()
        {
            return fileValue;
        }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -