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

org.jcodec.codecs.mpeg12.SegmentReader Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
package org.jcodec.codecs.mpeg12;
import org.jcodec.common.io.NIOUtils;

import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 * 
 * Pulls frames from MPEG elementary stream
 * 
 * @author The JCodec project
 * 
 */
public class SegmentReader {

    private ReadableByteChannel channel;
    private ByteBuffer buf;
    protected int curMarker;
    private int fetchSize;
    protected boolean done;
    private long pos;
    private int bytesInMarker;
    private int bufferIncrement = 1 << 15; // 32k

    public SegmentReader(ReadableByteChannel channel, int fetchSize) throws IOException {
        this.channel = channel;
        this.fetchSize = fetchSize;
        buf = NIOUtils.fetchFromChannel(channel, 4);
        pos = buf.remaining();
        curMarker = buf.getInt();
        bytesInMarker = 4;
    }
    
    
    
    // FOR TESTCASES
    public int getBufferIncrement() {
        return bufferIncrement;
    }

    // FOR TESTCASES
    public void setBufferIncrement(int bufferIncrement) {
        this.bufferIncrement = bufferIncrement;
    }



    public static enum State {
        MORE_DATA, DONE, STOP
    }
    
    /**
     * Reads one full segment till the next marker. Will read as much data as
     * the provided buffer fits, if the provided buffer doesn't fit all data
     * will return MORE_DATA.
     * 
     * @param out
     * @return
     * @throws IOException
     */
    public final State readToNextMarkerPartial(ByteBuffer out) throws IOException {
        if (done)
            return State.STOP;
        int skipOneMarker = curMarker >= 0x100 && curMarker <= 0x1ff ? 1 : 0;
        int written = out.position();
        do {
            while (buf.hasRemaining()) {
                if (curMarker >= 0x100 && curMarker <= 0x1ff) {
                    if (skipOneMarker == 0) {
                        return State.DONE;
                    }
                    --skipOneMarker;
                }
                if (!out.hasRemaining())
                    return State.MORE_DATA;
                out.put((byte) (curMarker >>> 24));
                curMarker = (curMarker << 8) | (buf.get() & 0xff);
            }
            buf = NIOUtils.fetchFromChannel(channel, fetchSize);
            pos += buf.remaining();
        } while (buf.hasRemaining());

        written = out.position() - written;
        if (written > 0 && curMarker >= 0x100 && curMarker <= 0x1ff)
            return State.DONE;

        for (; bytesInMarker > 0 && out.hasRemaining();) {
            out.put((byte) (curMarker >>> 24));
            curMarker = (curMarker << 8);
            --bytesInMarker;
            if (curMarker >= 0x100 && curMarker <= 0x1ff)
                return State.DONE;
        }

        if (bytesInMarker == 0) {
            done = true;
            return State.STOP;
        } else {
            return State.MORE_DATA;
        }
    }
    
        
    /**
     * Reads one full segment till the next marker. Will allocate the necessary
     * buffer to hold the full segment. Internally uses a growing collection of
     * smaller buffers since the segment size is intitially unkwnown.
     * 
     * @return
     * @throws IOException
     */
    public ByteBuffer readToNextMarkerNewBuffer() throws IOException {
        if (done)
            return null;
        List buffers = new ArrayList();
        readToNextMarkerBuffers(buffers);

        return NIOUtils.combineBuffers(buffers);
    }


    public void readToNextMarkerBuffers(List buffers) throws IOException {
        State state;
        do {
            ByteBuffer curBuffer = ByteBuffer.allocate(bufferIncrement);
            state = readToNextMarkerPartial(curBuffer);
            curBuffer.flip();
            buffers.add(curBuffer);
        } while (state == State.MORE_DATA);
    }

    public final boolean readToNextMarker(ByteBuffer out) throws IOException {
        State state = readToNextMarkerPartial(out);
        if(state == State.MORE_DATA)
            throw new BufferOverflowException();
        return state == State.DONE;
    }

    public final boolean skipToMarker() throws IOException {
        if (done)
            return false;
        do {
            while (buf.hasRemaining()) {
                curMarker = (curMarker << 8) | (buf.get() & 0xff);
                if (curMarker >= 0x100 && curMarker <= 0x1ff) {
                    return true;
                }
            }
            buf = NIOUtils.fetchFromChannel(channel, fetchSize);
            pos += buf.remaining();
        } while (buf.hasRemaining());
        done = true;

        return false;
    }

    public final boolean read(ByteBuffer out, int length) throws IOException {
        if (done)
            return false;
        do {
            while (buf.hasRemaining()) {
                if (length-- == 0)
                    return true;
                out.put((byte) (curMarker >>> 24));
                curMarker = (curMarker << 8) | (buf.get() & 0xff);
            }
            buf = NIOUtils.fetchFromChannel(channel, fetchSize);
            pos += buf.remaining();
        } while (buf.hasRemaining());
        out.putInt(curMarker);
        done = true;

        return false;
    }

    public final long curPos() {
        return pos - buf.remaining() - 4;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy