1 /* 2 * Copyright 2012 Sebastian Annies, Hamburg 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an AS IS BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.googlecode.mp4parser.authoring.tracks; 17 18 import com.coremedia.iso.boxes.*; 19 import com.googlecode.mp4parser.authoring.AbstractTrack; 20 import com.googlecode.mp4parser.authoring.Track; 21 import com.googlecode.mp4parser.authoring.TrackMetaData; 22 23 import java.nio.ByteBuffer; 24 import java.util.LinkedList; 25 import java.util.List; 26 27 /** 28 * Generates a Track that starts at fromSample and ends at toSample (exclusive). The user of this class 29 * has to make sure that the fromSample is a random access sample. 30 * <ul> 31 * <li>In AAC this is every single sample</li> 32 * <li>In H264 this is every sample that is marked in the SyncSampleBox</li> 33 * </ul> 34 */ 35 public class CroppedTrack extends AbstractTrack { 36 Track origTrack; 37 private int fromSample; 38 private int toSample; 39 private long[] syncSampleArray; 40 41 public CroppedTrack(Track origTrack, long fromSample, long toSample) { 42 this.origTrack = origTrack; 43 assert fromSample <= Integer.MAX_VALUE; 44 assert toSample <= Integer.MAX_VALUE; 45 this.fromSample = (int) fromSample; 46 this.toSample = (int) toSample; 47 } 48 49 public List<ByteBuffer> getSamples() { 50 return origTrack.getSamples().subList(fromSample, toSample); 51 } 52 53 public SampleDescriptionBox getSampleDescriptionBox() { 54 return origTrack.getSampleDescriptionBox(); 55 } 56 57 public List<TimeToSampleBox.Entry> getDecodingTimeEntries() { 58 if (origTrack.getDecodingTimeEntries() != null && !origTrack.getDecodingTimeEntries().isEmpty()) { 59 // todo optimize! too much long is allocated but then not used 60 long[] decodingTimes = TimeToSampleBox.blowupTimeToSamples(origTrack.getDecodingTimeEntries()); 61 long[] nuDecodingTimes = new long[toSample - fromSample]; 62 System.arraycopy(decodingTimes, fromSample, nuDecodingTimes, 0, toSample - fromSample); 63 64 LinkedList<TimeToSampleBox.Entry> returnDecodingEntries = new LinkedList<TimeToSampleBox.Entry>(); 65 66 for (long nuDecodingTime : nuDecodingTimes) { 67 if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getDelta() != nuDecodingTime) { 68 TimeToSampleBox.Entry e = new TimeToSampleBox.Entry(1, nuDecodingTime); 69 returnDecodingEntries.add(e); 70 } else { 71 TimeToSampleBox.Entry e = returnDecodingEntries.getLast(); 72 e.setCount(e.getCount() + 1); 73 } 74 } 75 return returnDecodingEntries; 76 } else { 77 return null; 78 } 79 } 80 81 public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() { 82 if (origTrack.getCompositionTimeEntries() != null && !origTrack.getCompositionTimeEntries().isEmpty()) { 83 int[] compositionTime = CompositionTimeToSample.blowupCompositionTimes(origTrack.getCompositionTimeEntries()); 84 int[] nuCompositionTimes = new int[toSample - fromSample]; 85 System.arraycopy(compositionTime, fromSample, nuCompositionTimes, 0, toSample - fromSample); 86 87 LinkedList<CompositionTimeToSample.Entry> returnDecodingEntries = new LinkedList<CompositionTimeToSample.Entry>(); 88 89 for (int nuDecodingTime : nuCompositionTimes) { 90 if (returnDecodingEntries.isEmpty() || returnDecodingEntries.getLast().getOffset() != nuDecodingTime) { 91 CompositionTimeToSample.Entry e = new CompositionTimeToSample.Entry(1, nuDecodingTime); 92 returnDecodingEntries.add(e); 93 } else { 94 CompositionTimeToSample.Entry e = returnDecodingEntries.getLast(); 95 e.setCount(e.getCount() + 1); 96 } 97 } 98 return returnDecodingEntries; 99 } else { 100 return null; 101 } 102 } 103 104 synchronized public long[] getSyncSamples() { 105 if (this.syncSampleArray == null) { 106 if (origTrack.getSyncSamples() != null && origTrack.getSyncSamples().length > 0) { 107 List<Long> syncSamples = new LinkedList<Long>(); 108 for (long l : origTrack.getSyncSamples()) { 109 if (l >= fromSample && l < toSample) { 110 syncSamples.add(l - fromSample); 111 } 112 } 113 syncSampleArray = new long[syncSamples.size()]; 114 for (int i = 0; i < syncSampleArray.length; i++) { 115 syncSampleArray[i] = syncSamples.get(i); 116 117 } 118 return syncSampleArray; 119 } else { 120 return null; 121 } 122 } else { 123 return this.syncSampleArray; 124 } 125 } 126 127 public List<SampleDependencyTypeBox.Entry> getSampleDependencies() { 128 if (origTrack.getSampleDependencies() != null && !origTrack.getSampleDependencies().isEmpty()) { 129 return origTrack.getSampleDependencies().subList(fromSample, toSample); 130 } else { 131 return null; 132 } 133 } 134 135 public TrackMetaData getTrackMetaData() { 136 return origTrack.getTrackMetaData(); 137 } 138 139 public String getHandler() { 140 return origTrack.getHandler(); 141 } 142 143 public Box getMediaHeaderBox() { 144 return origTrack.getMediaHeaderBox(); 145 } 146 147 public SubSampleInformationBox getSubsampleInformationBox() { 148 return origTrack.getSubsampleInformationBox(); 149 } 150 151 }