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