Home | History | Annotate | Download | only in adaptivestreaming
      1 package com.googlecode.mp4parser.authoring.adaptivestreaming;
      2 
      3 import com.coremedia.iso.boxes.OriginalFormatBox;
      4 import com.coremedia.iso.boxes.TimeToSampleBox;
      5 import com.coremedia.iso.boxes.sampleentry.SampleEntry;
      6 import com.googlecode.mp4parser.authoring.Movie;
      7 import com.googlecode.mp4parser.authoring.Track;
      8 import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;
      9 
     10 import java.io.IOException;
     11 import java.nio.ByteBuffer;
     12 import java.util.Arrays;
     13 import java.util.logging.Logger;
     14 
     15 import static com.googlecode.mp4parser.util.CastUtils.l2i;
     16 
     17 /**
     18  * Created with IntelliJ IDEA.
     19  * User: mstattma
     20  * Date: 17.08.12
     21  * Time: 02:51
     22  * To change this template use File | Settings | File Templates.
     23  */
     24 public abstract class AbstractManifestWriter implements ManifestWriter {
     25     private static final Logger LOG = Logger.getLogger(AbstractManifestWriter.class.getName());
     26 
     27     private FragmentIntersectionFinder intersectionFinder;
     28     protected long[] audioFragmentsDurations;
     29     protected long[] videoFragmentsDurations;
     30 
     31     protected AbstractManifestWriter(FragmentIntersectionFinder intersectionFinder) {
     32         this.intersectionFinder = intersectionFinder;
     33     }
     34 
     35     /**
     36      * Calculates the length of each fragment in the given <code>track</code> (as part of <code>movie</code>).
     37      *
     38      * @param track target of calculation
     39      * @param movie the <code>track</code> must be part of this <code>movie</code>
     40      * @return the duration of each fragment in track timescale
     41      */
     42     public long[] calculateFragmentDurations(Track track, Movie movie) {
     43         long[] startSamples = intersectionFinder.sampleNumbers(track, movie);
     44         long[] durations = new long[startSamples.length];
     45         int currentFragment = 0;
     46         int currentSample = 1; // sync samples start with 1 !
     47 
     48         for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
     49             for (int max = currentSample + l2i(entry.getCount()); currentSample < max; currentSample++) {
     50                 // in this loop we go through the entry.getCount() samples starting from current sample.
     51                 // the next entry.getCount() samples have the same decoding time.
     52                 if (currentFragment != startSamples.length - 1 && currentSample == startSamples[currentFragment + 1]) {
     53                     // we are not in the last fragment && the current sample is the start sample of the next fragment
     54                     currentFragment++;
     55                 }
     56                 durations[currentFragment] += entry.getDelta();
     57 
     58 
     59             }
     60         }
     61         return durations;
     62 
     63     }
     64 
     65     public long getBitrate(Track track) {
     66         long bitrate = 0;
     67         for (ByteBuffer sample : track.getSamples()) {
     68             bitrate += sample.limit();
     69         }
     70         bitrate *= 8; // from bytes to bits
     71         bitrate /= ((double) getDuration(track)) / track.getTrackMetaData().getTimescale(); // per second
     72         return bitrate;
     73     }
     74 
     75     protected static long getDuration(Track track) {
     76         long duration = 0;
     77         for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
     78             duration += entry.getCount() * entry.getDelta();
     79         }
     80         return duration;
     81     }
     82 
     83     protected long[] checkFragmentsAlign(long[] referenceTimes, long[] checkTimes) throws IOException {
     84 
     85         if (referenceTimes == null || referenceTimes.length == 0) {
     86             return checkTimes;
     87         }
     88         long[] referenceTimesMinusLast = new long[referenceTimes.length - 1];
     89         System.arraycopy(referenceTimes, 0, referenceTimesMinusLast, 0, referenceTimes.length - 1);
     90         long[] checkTimesMinusLast = new long[checkTimes.length - 1];
     91         System.arraycopy(checkTimes, 0, checkTimesMinusLast, 0, checkTimes.length - 1);
     92 
     93         if (!Arrays.equals(checkTimesMinusLast, referenceTimesMinusLast)) {
     94             String log = "";
     95             log += (referenceTimes.length);
     96             log += ("Reference     :  [");
     97             for (long l : referenceTimes) {
     98                 log += (String.format("%10d,", l));
     99             }
    100             log += ("]");
    101             LOG.warning(log);
    102             log = "";
    103 
    104             log += (checkTimes.length);
    105             log += ("Current       :  [");
    106             for (long l : checkTimes) {
    107                 log += (String.format("%10d,", l));
    108             }
    109             log += ("]");
    110             LOG.warning(log);
    111             throw new IOException("Track does not have the same fragment borders as its predecessor.");
    112 
    113         } else {
    114             return checkTimes;
    115         }
    116     }
    117 
    118     protected String getFormat(SampleEntry se) {
    119         String type = se.getType();
    120         if (type.equals("encv") || type.equals("enca") || type.equals("encv")) {
    121             OriginalFormatBox frma = se.getBoxes(OriginalFormatBox.class, true).get(0);
    122             type = frma.getDataFormat();
    123         }
    124         return type;
    125     }
    126 }
    127