Package org.jaudiotagger.tag.id3

Source Code of org.jaudiotagger.tag.id3.ID3Unsynchronization

package org.jaudiotagger.tag.id3;

import org.jaudiotagger.audio.mp3.MPEGFrameHeader;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
* Performs unsynchronization and synchronization tasks on a buffer.
* <p/>
* Is currently required for V23Tags and V24Frames
*/
public class ID3Unsynchronization {
    //Logger
    public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3");


    /**
     * Check if a byte array will require unsynchronization before being written as a tag.
     * If the byte array contains any $FF $E0 bytes, then it will require unsynchronization.
     *
     * @param abySource the byte array to be examined
     * @return true if unsynchronization is required, false otherwise
     */
    public static boolean requiresUnsynchronization(byte[] abySource) {
        for (int i = 0; i < abySource.length - 1; i++) {
            if (((abySource[i] & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) && ((abySource[i + 1] & MPEGFrameHeader.SYNC_BYTE2) == MPEGFrameHeader.SYNC_BYTE2)) {
                if (logger.isLoggable(Level.FINEST)) {
                    //logger.finest("Unsynchronisation required found bit at:" + i);
                }
                return true;
            }
        }

        return false;
    }

    /**
     * Unsynchronize an array of bytes, this should only be called if the decision has already been made to
     * unsynchronize the byte array
     * <p/>
     * In order to prevent a media player from incorrectly interpreting the contents of a tag, all $FF bytes
     * followed by a byte with value >=224 must be followed by a $00 byte (thus, $FF $F0 sequences become $FF $00 $F0).
     * Additionally because unsynchronisation is being applied any existing $FF $00 have to be converted to
     * $FF $00 $00
     *
     * @param abySource a byte array to be unsynchronized
     * @return a unsynchronized representation of the source
     */
    public static byte[] unsynchronize(byte[] abySource) {
        ByteArrayInputStream input = new ByteArrayInputStream(abySource);
        ByteArrayOutputStream output = new ByteArrayOutputStream(abySource.length);

        int count = 0;
        while (input.available() > 0) {
            int firstByte = input.read();
            count++;
            output.write(firstByte);
            if ((firstByte & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) {
                // if byte is $FF, we must check the following byte if there is one
                if (input.available() > 0) {
                    input.mark(1)// remember where we were, if we don't need to unsynchronize
                    int secondByte = input.read();
                    if ((secondByte & MPEGFrameHeader.SYNC_BYTE2) == MPEGFrameHeader.SYNC_BYTE2) {
                        // we need to unsynchronize here
                        if (logger.isLoggable(Level.FINEST)) {
                            //logger.finest("Writing unsynchronisation bit at:" + count);
                        }
                        output.write(0);

                    } else if (secondByte == 0) {
                        // we need to unsynchronize here
                        if (logger.isLoggable(Level.FINEST)) {
                            //logger.finest("Inserting zero unsynchronisation bit at:" + count);
                        }
                        output.write(0);
                    }
                    input.reset();
                }
            }
        }
        // if we needed to unsynchronize anything, and this tag ends with 0xff, we have to append a zero byte,
        // which will be removed on de-unsynchronization later
        if ((abySource[abySource.length - 1] & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) {
            //logger.finest("Adding unsynchronisation bit at end of stream");
            output.write(0);
        }
        return output.toByteArray();
    }


    /**
     * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised
     * <p/>
     * Any patterns of the form $FF $00 should be replaced by $FF
     *
     * @param source a ByteBuffer to be unsynchronized
     * @return a synchronized representation of the source
     */
    /*
    public static ByteBuffer synchronize(ByteBuffer source)
    {
        long start = System.nanoTime();

        int bufferSize = source.limit();
        ByteArrayOutputStream oBAOS = new ByteArrayOutputStream(bufferSize);
        int position = 0;
        while (position < bufferSize)
        {
            int byteValue = source.get();
            position ++;
            oBAOS.write(byteValue);
            if ((byteValue & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1)
            {
                // we are skipping if $00 byte but check not an end of stream
                if (position < bufferSize)
                {
                    int unsyncByteValue = source.get();
                    position++;
                    //If its the null byte we just ignore it
                    if (unsyncByteValue != 0)
                    {
                        oBAOS.write(unsyncByteValue);
                    }
                }
            }
        }
        long time = System.nanoTime() - start;
        ByteBuffer bb = ByteBuffer.wrap(oBAOS.toByteArray());
        System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), bb.limit());
        return bb;
    }
    */

    /**
     * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised
     * <p/>
     * Any patterns of the form $FF $00 should be replaced by $FF
     *
     * @param source a ByteBuffer to be unsynchronized
     * @return a synchronized representation of the source
     */
    /*
    public static ByteBuffer synchronize(ByteBuffer source)
    {
        long start = System.nanoTime();

        int bufferSize = source.limit();
        ByteBuffer output = ByteBuffer.allocate(bufferSize);
        int position = 0;
        int offset = 0;
        int length = 0;
        while (position < bufferSize)
        {
            int byteValue = source.get();
            position++;
            length++;
            if ((byteValue & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1)
            {
                // we are skipping if $00 byte but check not an end of stream
                if (position < bufferSize)
                {
                    int unsyncByteValue = source.get();
                    position++;
                    //If this is null byte, then write upto this point
                    if (unsyncByteValue == 0)
                    {
                        output.put(source.array(), source.arrayOffset() + offset, length);
                        offset = position;
                        length = 0;
                    }
                    else
                    {
                        length++;
                    }
                }
            }
        }
        if (length > 0)
        {
            output.put(source.array(), source.arrayOffset() + offset, length);
        }
        output.flip();
        long time = System.nanoTime() - start;
        System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), output.limit());
        return output;
    }
    */

    /**
     * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised
     * <p/>
     * Any patterns of the form $FF $00 should be replaced by $FF
     *
     * @param source a ByteBuffer to be unsynchronized
     * @return a synchronized representation of the source
     */

    public static ByteBuffer synchronize(ByteBuffer source) {
        //long start = System.nanoTime();

        int len = source.remaining();
        byte[] bytes = new byte[len + 1]; // an extra byte saves a check later.
        source.get(bytes, 0, len);
        int from = 0, to = 0;
        boolean copy = true; // whether to copy the byte, if false, check the byte != 0.
        while (from < len) {
            byte byteValue = bytes[from++];
            if (copy || byteValue != 0) bytes[to++] = byteValue;
            copy = ((byteValue & MPEGFrameHeader.SYNC_BYTE1) != MPEGFrameHeader.SYNC_BYTE1);
        }

        ByteBuffer bb2 = ByteBuffer.wrap(bytes, 0, to);
        //long time = System.nanoTime() - start;
        //System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), bb2.limit());
        return bb2;
    }

}
TOP

Related Classes of org.jaudiotagger.tag.id3.ID3Unsynchronization

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.