private InterleaveChunkMdat(Movie movie, Map<Track, int[]> chunks, long contentSize) { this.contentSize = contentSize; this.tracks = movie.getTracks(); List<Track> tracks = new ArrayList<Track>(chunks.keySet()); Collections.sort( tracks, new Comparator<Track>() { public int compare(Track o1, Track o2) { return l2i(o1.getTrackMetaData().getTrackId() - o2.getTrackMetaData().getTrackId()); } }); Map<Track, Integer> trackToChunk = new HashMap<Track, Integer>(); Map<Track, Integer> trackToSample = new HashMap<Track, Integer>(); Map<Track, Double> trackToTime = new HashMap<Track, Double>(); for (Track track : tracks) { trackToChunk.put(track, 0); trackToSample.put(track, 0); trackToTime.put(track, 0.0); } while (true) { Track nextChunksTrack = null; for (Track track : tracks) { if ((nextChunksTrack == null || trackToTime.get(track) < trackToTime.get(nextChunksTrack)) && // either first OR track's next chunk's starttime is smaller than nextTrack's next // chunks starttime // AND their need to be chunks left! (trackToChunk.get(track) < chunks.get(track).length)) { nextChunksTrack = track; } } if (nextChunksTrack == null) { break; } // found the next one int nextChunksIndex = trackToChunk.get(nextChunksTrack); int numberOfSampleInNextChunk = chunks.get(nextChunksTrack)[nextChunksIndex]; int startSample = trackToSample.get(nextChunksTrack); double time = trackToTime.get(nextChunksTrack); for (int j = startSample; j < startSample + numberOfSampleInNextChunk; j++) { time += (double) nextChunksTrack.getSampleDurations()[j] / nextChunksTrack.getTrackMetaData().getTimescale(); } chunkList.add( nextChunksTrack .getSamples() .subList(startSample, startSample + numberOfSampleInNextChunk)); trackToChunk.put(nextChunksTrack, nextChunksIndex + 1); trackToSample.put(nextChunksTrack, startSample + numberOfSampleInNextChunk); trackToTime.put(nextChunksTrack, time); } }
protected Box createStbl(Track track, Movie movie, Map<Track, int[]> chunks) { SampleTableBox stbl = new SampleTableBox(); createStsd(track, stbl); createStts(track, stbl); createCtts(track, stbl); createStss(track, stbl); createSdtp(track, stbl); createStsc(track, chunks, stbl); createStsz(track, stbl); createStco(track, movie, chunks, stbl); Map<String, List<GroupEntry>> groupEntryFamilies = new HashMap<String, List<GroupEntry>>(); for (Map.Entry<GroupEntry, long[]> sg : track.getSampleGroups().entrySet()) { String type = sg.getKey().getType(); List<GroupEntry> groupEntries = groupEntryFamilies.get(type); if (groupEntries == null) { groupEntries = new ArrayList<GroupEntry>(); groupEntryFamilies.put(type, groupEntries); } groupEntries.add(sg.getKey()); } for (Map.Entry<String, List<GroupEntry>> sg : groupEntryFamilies.entrySet()) { SampleGroupDescriptionBox sgdb = new SampleGroupDescriptionBox(); String type = sg.getKey(); sgdb.setGroupEntries(sg.getValue()); SampleToGroupBox sbgp = new SampleToGroupBox(); sbgp.setGroupingType(type); SampleToGroupBox.Entry last = null; for (int i = 0; i < track.getSamples().size(); i++) { int index = 0; for (int j = 0; j < sg.getValue().size(); j++) { GroupEntry groupEntry = sg.getValue().get(j); long[] sampleNums = track.getSampleGroups().get(groupEntry); if (Arrays.binarySearch(sampleNums, i) >= 0) { index = j + 1; } } if (last == null || last.getGroupDescriptionIndex() != index) { last = new SampleToGroupBox.Entry(1, index); sbgp.getEntries().add(last); } else { last.setSampleCount(last.getSampleCount() + 1); } } stbl.addBox(sgdb); stbl.addBox(sbgp); } if (track instanceof CencEncryptedTrack) { createCencBoxes((CencEncryptedTrack) track, stbl, chunks.get(track)); } createSubs(track, stbl); return stbl; }
protected void createStsc(Track track, Map<Track, int[]> chunks, SampleTableBox stbl) { int[] tracksChunkSizes = chunks.get(track); SampleToChunkBox stsc = new SampleToChunkBox(); stsc.setEntries(new LinkedList<SampleToChunkBox.Entry>()); long lastChunkSize = Integer.MIN_VALUE; // to be sure the first chunks hasn't got the same size for (int i = 0; i < tracksChunkSizes.length; i++) { // The sample description index references the sample description box // that describes the samples of this chunk. My Tracks cannot have more // than one sample description box. Therefore 1 is always right // the first chunk has the number '1' if (lastChunkSize != tracksChunkSizes[i]) { stsc.getEntries().add(new SampleToChunkBox.Entry(i + 1, tracksChunkSizes[i], 1)); lastChunkSize = tracksChunkSizes[i]; } } stbl.addBox(stsc); }
protected void createStco( Track targetTrack, Movie movie, Map<Track, int[]> chunks, SampleTableBox stbl) { if (chunkOffsetBoxes.get(targetTrack) == null) { // The ChunkOffsetBox we create here is just a stub // since we haven't created the whole structure we can't tell where the // first chunk starts (mdat box). So I just let the chunk offset // start at zero and I will add the mdat offset later. long offset = 0; // all tracks have the same number of chunks if (LOG.isLoggable(Level.FINE)) { LOG.fine( "Calculating chunk offsets for track_" + targetTrack.getTrackMetaData().getTrackId()); } List<Track> tracks = new ArrayList<Track>(chunks.keySet()); Collections.sort( tracks, new Comparator<Track>() { public int compare(Track o1, Track o2) { return l2i(o1.getTrackMetaData().getTrackId() - o2.getTrackMetaData().getTrackId()); } }); Map<Track, Integer> trackToChunk = new HashMap<Track, Integer>(); Map<Track, Integer> trackToSample = new HashMap<Track, Integer>(); Map<Track, Double> trackToTime = new HashMap<Track, Double>(); for (Track track : tracks) { trackToChunk.put(track, 0); trackToSample.put(track, 0); trackToTime.put(track, 0.0); chunkOffsetBoxes.put(track, new StaticChunkOffsetBox()); } while (true) { Track nextChunksTrack = null; for (Track track : tracks) { // This always chooses the least progressed track if ((nextChunksTrack == null || trackToTime.get(track) < trackToTime.get(nextChunksTrack)) && // either first OR track's next chunk's starttime is smaller than nextTrack's next // chunks starttime // AND their need to be chunks left! (trackToChunk.get(track) < chunks.get(track).length)) { nextChunksTrack = track; } } if (nextChunksTrack == null) { break; // no next } // found the next one ChunkOffsetBox chunkOffsetBox = chunkOffsetBoxes.get(nextChunksTrack); chunkOffsetBox.setChunkOffsets( Mp4Arrays.copyOfAndAppend(chunkOffsetBox.getChunkOffsets(), offset)); int nextChunksIndex = trackToChunk.get(nextChunksTrack); int numberOfSampleInNextChunk = chunks.get(nextChunksTrack)[nextChunksIndex]; int startSample = trackToSample.get(nextChunksTrack); double time = trackToTime.get(nextChunksTrack); for (int j = startSample; j < startSample + numberOfSampleInNextChunk; j++) { offset += track2SampleSizes.get(nextChunksTrack)[j]; time += (double) nextChunksTrack.getSampleDurations()[j] / nextChunksTrack.getTrackMetaData().getTimescale(); } trackToChunk.put(nextChunksTrack, nextChunksIndex + 1); trackToSample.put(nextChunksTrack, startSample + numberOfSampleInNextChunk); trackToTime.put(nextChunksTrack, time); } } stbl.addBox(chunkOffsetBoxes.get(targetTrack)); }