diff options
Diffstat (limited to 'isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base')
-rw-r--r-- | isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base new file mode 100644 index 0000000..a7f7b59 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/mdat/.svn/text-base/SampleList.java.svn-base @@ -0,0 +1,227 @@ +package com.coremedia.iso.boxes.mdat; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.boxes.*; +import com.coremedia.iso.boxes.fragment.*; + +import java.nio.ByteBuffer; +import java.util.*; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + +/** + * Creates a list of <code>ByteBuffer</code>s that represent the samples of a given track. + */ +public class SampleList extends AbstractList<ByteBuffer> { + + + long[] offsets; + long[] sizes; + + IsoFile isoFile; + HashMap<MediaDataBox, Long> mdatStartCache = new HashMap<MediaDataBox, Long>(); + HashMap<MediaDataBox, Long> mdatEndCache = new HashMap<MediaDataBox, Long>(); + MediaDataBox[] mdats; + + /** + * Gets a sorted random access optimized list of all sample offsets. + * Basically it is a map from sample number to sample offset. + * + * @return the sorted list of sample offsets + */ + public long[] getOffsetKeys() { + return offsets; + } + + + public SampleList(TrackBox trackBox) { + initIsoFile(trackBox.getIsoFile()); // where are we? + + // first we get all sample from the 'normal' MP4 part. + // if there are none - no problem. + SampleSizeBox sampleSizeBox = trackBox.getSampleTableBox().getSampleSizeBox(); + ChunkOffsetBox chunkOffsetBox = trackBox.getSampleTableBox().getChunkOffsetBox(); + SampleToChunkBox sampleToChunkBox = trackBox.getSampleTableBox().getSampleToChunkBox(); + + + final long[] chunkOffsets = chunkOffsetBox != null ? chunkOffsetBox.getChunkOffsets() : new long[0]; + if (sampleToChunkBox != null && sampleToChunkBox.getEntries().size() > 0 && + chunkOffsets.length > 0 && sampleSizeBox != null && sampleSizeBox.getSampleCount() > 0) { + long[] numberOfSamplesInChunk = sampleToChunkBox.blowup(chunkOffsets.length); + + int sampleIndex = 0; + + if (sampleSizeBox.getSampleSize() > 0) { + sizes = new long[l2i(sampleSizeBox.getSampleCount())]; + Arrays.fill(sizes, sampleSizeBox.getSampleSize()); + } else { + sizes = sampleSizeBox.getSampleSizes(); + } + offsets = new long[sizes.length]; + + for (int i = 0; i < numberOfSamplesInChunk.length; i++) { + long thisChunksNumberOfSamples = numberOfSamplesInChunk[i]; + long sampleOffset = chunkOffsets[i]; + for (int j = 0; j < thisChunksNumberOfSamples; j++) { + long sampleSize = sizes[sampleIndex]; + offsets[sampleIndex] = sampleOffset; + sampleOffset += sampleSize; + sampleIndex++; + } + } + + } + + // Next we add all samples from the fragments + // in most cases - I've never seen it different it's either normal or fragmented. + List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class); + + if (movieExtendsBoxes.size() > 0) { + Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>(); + List<TrackExtendsBox> trackExtendsBoxes = movieExtendsBoxes.get(0).getBoxes(TrackExtendsBox.class); + for (TrackExtendsBox trackExtendsBox : trackExtendsBoxes) { + if (trackExtendsBox.getTrackId() == trackBox.getTrackHeaderBox().getTrackId()) { + for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) { + offsets2Sizes.putAll(getOffsets(movieFragmentBox, trackBox.getTrackHeaderBox().getTrackId(), trackExtendsBox)); + } + } + } + + if (sizes == null || offsets == null) { + sizes = new long[0]; + offsets = new long[0]; + } + + splitToArrays(offsets2Sizes); + } + + // We have now a map from all sample offsets to their sizes + } + + private void splitToArrays(Map<Long, Long> offsets2Sizes) { + List<Long> keys = new ArrayList<Long>(offsets2Sizes.keySet()); + Collections.sort(keys); + + long[] nuSizes = new long[sizes.length + keys.size()]; + System.arraycopy(sizes, 0, nuSizes, 0, sizes.length); + long[] nuOffsets = new long[offsets.length + keys.size()]; + System.arraycopy(offsets, 0, nuOffsets, 0, offsets.length); + for (int i = 0; i < keys.size(); i++) { + nuOffsets[i + offsets.length] = keys.get(i); + nuSizes[i + sizes.length] = offsets2Sizes.get(keys.get(i)); + } + sizes = nuSizes; + offsets = nuOffsets; + } + + public SampleList(TrackFragmentBox traf) { + sizes = new long[0]; + offsets = new long[0]; + Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>(); + initIsoFile(traf.getIsoFile()); + + final List<MovieFragmentBox> movieFragmentBoxList = isoFile.getBoxes(MovieFragmentBox.class); + + final long trackId = traf.getTrackFragmentHeaderBox().getTrackId(); + for (MovieFragmentBox moof : movieFragmentBoxList) { + final List<TrackFragmentHeaderBox> trackFragmentHeaderBoxes = moof.getTrackFragmentHeaderBoxes(); + for (TrackFragmentHeaderBox tfhd : trackFragmentHeaderBoxes) { + if (tfhd.getTrackId() == trackId) { + offsets2Sizes.putAll(getOffsets(moof, trackId, null)); + } + } + } + splitToArrays(offsets2Sizes); + } + + private void initIsoFile(IsoFile isoFile) { + this.isoFile = isoFile; + // find all mdats first to be able to use them later with explicitly looking them up + long currentOffset = 0; + LinkedList<MediaDataBox> mdats = new LinkedList<MediaDataBox>(); + for (Box b : this.isoFile.getBoxes()) { + long currentSize = b.getSize(); + if ("mdat".equals(b.getType())) { + if (b instanceof MediaDataBox) { + long contentOffset = currentOffset + ((MediaDataBox) b).getHeader().limit(); + mdatStartCache.put((MediaDataBox) b, contentOffset); + mdatEndCache.put((MediaDataBox) b, contentOffset + currentSize); + mdats.add((MediaDataBox) b); + } else { + throw new RuntimeException("Sample need to be in mdats and mdats need to be instanceof MediaDataBox"); + } + } + currentOffset += currentSize; + } + this.mdats = mdats.toArray(new MediaDataBox[mdats.size()]); + } + + + @Override + public int size() { + return sizes.length; + } + + + @Override + public ByteBuffer get(int index) { + // it is a two stage lookup: from index to offset to size + long offset = offsets[index]; + int sampleSize = l2i(sizes[index]); + + for (MediaDataBox mediaDataBox : mdats) { + long start = mdatStartCache.get(mediaDataBox); + long end = mdatEndCache.get(mediaDataBox); + if ((start <= offset) && (offset + sampleSize <= end)) { + return mediaDataBox.getContent(offset - start, sampleSize); + } + } + + throw new RuntimeException("The sample with offset " + offset + " and size " + sampleSize + " is NOT located within an mdat"); + } + + Map<Long, Long> getOffsets(MovieFragmentBox moof, long trackId, TrackExtendsBox trex) { + Map<Long, Long> offsets2Sizes = new HashMap<Long, Long>(); + List<TrackFragmentBox> traf = moof.getBoxes(TrackFragmentBox.class); + for (TrackFragmentBox trackFragmentBox : traf) { + if (trackFragmentBox.getTrackFragmentHeaderBox().getTrackId() == trackId) { + long baseDataOffset; + if (trackFragmentBox.getTrackFragmentHeaderBox().hasBaseDataOffset()) { + baseDataOffset = trackFragmentBox.getTrackFragmentHeaderBox().getBaseDataOffset(); + } else { + baseDataOffset = moof.getOffset(); + } + + for (TrackRunBox trun : trackFragmentBox.getBoxes(TrackRunBox.class)) { + long sampleBaseOffset = baseDataOffset + trun.getDataOffset(); + final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox(); + + long offset = 0; + for (TrackRunBox.Entry entry : trun.getEntries()) { + final long sampleSize; + if (trun.isSampleSizePresent()) { + sampleSize = entry.getSampleSize(); + offsets2Sizes.put(offset + sampleBaseOffset, sampleSize); + offset += sampleSize; + } else { + if (tfhd.hasDefaultSampleSize()) { + sampleSize = tfhd.getDefaultSampleSize(); + offsets2Sizes.put(offset + sampleBaseOffset, sampleSize); + offset += sampleSize; + } else { + if (trex == null) { + throw new RuntimeException("File doesn't contain trex box but track fragments aren't fully self contained. Cannot determine sample size."); + } + sampleSize = trex.getDefaultSampleSize(); + offsets2Sizes.put(offset + sampleBaseOffset, sampleSize); + offset += sampleSize; + } + } + } + } + } + } + return offsets2Sizes; + } + +}
\ No newline at end of file |