FileDocCategorySizeDatePackage
MediaDataBox.javaAPI Docmp4parser 1.0-RC-177742Wed Dec 19 20:10:38 GMT 2012com.coremedia.iso.boxes.mdat

MediaDataBox

public final class MediaDataBox extends Object implements com.coremedia.iso.boxes.Box
This box contains the media data. In video tracks, this box would contain video frames. A presentation may contain zero or more Media Data Boxes. The actual media data follows the type field; its structure is described by the metadata (see {@link com.coremedia.iso.boxes.SampleTableBox}).
In large presentations, it may be desirable to have more data in this box than a 32-bit size would permit. In this case, the large variant of the size field is used.
There may be any number of these boxes in the file (including zero, if all the media data is in other files). The metadata refers to media data by its absolute offset within the file (see {@link com.coremedia.iso.boxes.StaticChunkOffsetBox}); so Media Data Box headers and free space may easily be skipped, and files without any box structure may also be referenced and used.

Fields Summary
private static Logger
LOG
public static final String
TYPE
public static final int
BUFFER_SIZE
com.coremedia.iso.boxes.ContainerBox
parent
ByteBuffer
header
private FileChannel
fileChannel
private long
startPosition
private long
contentSize
private ByteBuffer
content
If the whole content is just in one mapped buffer keep a strong reference to it so it is not evicted from the cache.
ByteBuffer
cacheSliceCurrentlyInUse
long
cacheSliceCurrentlyInUseStart
Constructors Summary
Methods Summary
private booleancheckStillOk()
If someone use the same file as source and sink it could the case that inserting a few bytes before the mdat results in overwriting data we still need to write this mdat here. This method just makes sure that we haven't already overwritten the mdat contents.

return
true if ok

        try {
            fileChannel.position(startPosition - header.limit());
            ByteBuffer h2 = ByteBuffer.allocate(header.limit());
            fileChannel.read(h2);
            header.rewind();
            h2.rewind();
            assert h2.equals(header) : "It seems that the content I want to read has already been overwritten.";
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

    
public voidgetBox(java.nio.channels.WritableByteChannel writableByteChannel)

        if (fileChannel != null) {
            assert checkStillOk();
            transfer(fileChannel, startPosition - header.limit(), contentSize + header.limit(), writableByteChannel);
        } else {
            header.rewind();
            writableByteChannel.write(header);
            writableByteChannel.write(content);
        }
    
public synchronized java.nio.ByteBuffergetContent(long offset, int length)


           
        // most likely the last used cache slice will be used again
        if (cacheSliceCurrentlyInUseStart <= offset && cacheSliceCurrentlyInUse != null && offset + length <= cacheSliceCurrentlyInUseStart + cacheSliceCurrentlyInUse.limit()) {
            ByteBuffer cachedSample = cacheSliceCurrentlyInUse.asReadOnlyBuffer();
            cachedSample.position((int) (offset - cacheSliceCurrentlyInUseStart));
            cachedSample.mark();
            cachedSample.limit((int) (offset - cacheSliceCurrentlyInUseStart) + length);
            return cachedSample;
        }

        // CACHE MISS
        ByteBuffer cacheEntry;
        try {
            // Just mapping 10MB at a time. Seems reasonable.
            cacheEntry = fileChannel.map(FileChannel.MapMode.READ_ONLY, startPosition + offset, Math.min(BUFFER_SIZE, contentSize - offset));
        } catch (IOException e1) {
            LOG.fine("Even mapping just 10MB of the source file into the memory failed. " + e1);
            throw new RuntimeException(
                    "Delayed reading of mdat content failed. Make sure not to close " +
                            "the FileChannel that has been used to create the IsoFile!", e1);
        }
        cacheSliceCurrentlyInUse = cacheEntry;
        cacheSliceCurrentlyInUseStart = offset;
        ByteBuffer cachedSample = cacheSliceCurrentlyInUse.asReadOnlyBuffer();
        cachedSample.position(0);
        cachedSample.mark();
        cachedSample.limit(length);
        return cachedSample;
    
public longgetDataEndPosition()

        return startPosition + contentSize;
    
public longgetDataStartPosition()

        return startPosition;
    
public java.nio.ByteBuffergetHeader()

        return header;
    
public com.coremedia.iso.boxes.ContainerBoxgetParent()


       
        return parent;
    
public longgetSize()

        long size = header.limit();
        size += contentSize;
        return size;
    
public java.lang.StringgetType()

        return TYPE;
    
public voidparse(java.nio.channels.ReadableByteChannel readableByteChannel, java.nio.ByteBuffer header, long contentSize, com.coremedia.iso.BoxParser boxParser)

        this.header = header;
        this.contentSize = contentSize;

        if (readableByteChannel instanceof FileChannel && (contentSize > AbstractBox.MEM_MAP_THRESHOLD)) {
            this.fileChannel = ((FileChannel) readableByteChannel);
            this.startPosition = ((FileChannel) readableByteChannel).position();
            ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize);
        } else {
            content = ChannelHelper.readFully(readableByteChannel, l2i(contentSize));
            startPosition = 0;
            for (Box box : this.getParent().getBoxes()) {
                startPosition += box.getSize();
            }
            startPosition += header.limit();
            cacheSliceCurrentlyInUse = content;
            cacheSliceCurrentlyInUseStart = 0;
        }
    
public voidsetParent(com.coremedia.iso.boxes.ContainerBox parent)

        this.parent = parent;
    
private static voidtransfer(java.nio.channels.FileChannel from, long position, long count, java.nio.channels.WritableByteChannel to)

        long maxCount = (64 * 1024 * 1024) - (32 * 1024);
        // Transfer data in chunks a bit less than 64MB
        // People state that this is a kind of magic number on Windows.
        // I don't care. The size seems reasonable.
        long offset = 0;
        while (offset < count) {
            offset += from.transferTo(position + offset, Math.min(maxCount, count - offset), to);
        }