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

org.jcodec.containers.mp4.SampleOffsetUtils Maven / Gradle / Ivy

The newest version!
package org.jcodec.containers.mp4;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.containers.mp4.boxes.Box;
import org.jcodec.containers.mp4.boxes.ChunkOffsetsBox;
import org.jcodec.containers.mp4.boxes.MediaInfoBox;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.NodeBox;
import org.jcodec.containers.mp4.boxes.SampleSizesBox;
import org.jcodec.containers.mp4.boxes.SampleToChunkBox;
import org.jcodec.containers.mp4.boxes.SampleToChunkBox.SampleToChunkEntry;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 * 
 * @author The JCodec project
 * 
 */
public class SampleOffsetUtils {

    public static ByteBuffer getSampleData(int sample, File file) throws IOException {
        MovieBox moov = MP4Util.parseMovie(file);
        MediaInfoBox minf = moov.getAudioTracks().get(0).getMdia().getMinf();
        ChunkOffsetsBox stco = NodeBox.findFirstPath(minf, ChunkOffsetsBox.class, Box.path("stbl.stco"));
        SampleToChunkBox stsc = NodeBox.findFirstPath(minf, SampleToChunkBox.class, Box.path("stbl.stsc"));
        SampleSizesBox stsz = NodeBox.findFirstPath(minf, SampleSizesBox.class, Box.path("stbl.stsz"));
        long sampleOffset = getSampleOffset(sample, stsc, stco, stsz);
        MappedByteBuffer map = NIOUtils.mapFile(file);
        map.position((int) sampleOffset);
        map.limit(map.position() + stsz.getSizes()[sample]);
        return map;
    }

    public static long getSampleOffset(int sample, SampleToChunkBox stsc, ChunkOffsetsBox stco, SampleSizesBox stsz) {
        int chunkBySample = getChunkBySample(sample, stco, stsc);
        int firstSampleAtChunk = getFirstSampleAtChunk(chunkBySample, stsc, stco);
        long offset = stco.getChunkOffsets()[chunkBySample - 1];
        int[] sizes = stsz.getSizes();
        for (int i = firstSampleAtChunk; i < sample; i++) {
            offset += sizes[i];
        }
        return offset;
    }

    public static int getFirstSampleAtChunk(int chunk, SampleToChunkBox stsc, ChunkOffsetsBox stco) {
        int chunks = stco.getChunkOffsets().length;
        int samples = 0;
        for (int i = 1; i <= chunks; i++) {
            if (i == chunk) {
                break;
            }
            int samplesInChunk = getSamplesInChunk(i, stsc);
            samples += samplesInChunk;
        }
        return samples;
    }

    public static int getChunkBySample(int sampleOfInterest, ChunkOffsetsBox stco, SampleToChunkBox stsc) {
        int chunks = stco.getChunkOffsets().length;
        int startSample = 0;
        int endSample = 0;
        for (int i = 1; i <= chunks; i++) {
            int samplesInChunk = getSamplesInChunk(i, stsc);
            endSample = startSample + samplesInChunk;
            if (sampleOfInterest >= startSample && sampleOfInterest < endSample) {
                return i;
            }
            startSample = endSample;
        }
        return -1;
    }

    public static int getSamplesInChunk(int chunk, SampleToChunkBox stsc) {
        //TODO this is faster with binary search 
        SampleToChunkEntry[] sampleToChunk = stsc.getSampleToChunk();
        int sampleCount = 0;
        for (SampleToChunkEntry sampleToChunkEntry : sampleToChunk) {
            if (sampleToChunkEntry.getFirst() > chunk) {
                return sampleCount;
            }
            sampleCount = sampleToChunkEntry.getCount();
        }
        return sampleCount;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy