Home | History | Annotate | Download | only in tracks
      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 }