blob: 6ee4ffaca550e43a735d5c30f82f6c79201dc65f [file] [log] [blame]
package com.googlecode.mp4parser.authoring.adaptivestreaming;
import com.coremedia.iso.boxes.OriginalFormatBox;
import com.coremedia.iso.boxes.TimeToSampleBox;
import com.coremedia.iso.boxes.sampleentry.SampleEntry;
import com.googlecode.mp4parser.authoring.Movie;
import com.googlecode.mp4parser.authoring.Track;
import com.googlecode.mp4parser.authoring.builder.FragmentIntersectionFinder;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.logging.Logger;
import static com.googlecode.mp4parser.util.CastUtils.l2i;
/**
* Created with IntelliJ IDEA.
* User: mstattma
* Date: 17.08.12
* Time: 02:51
* To change this template use File | Settings | File Templates.
*/
public abstract class AbstractManifestWriter implements ManifestWriter {
private static final Logger LOG = Logger.getLogger(AbstractManifestWriter.class.getName());
private FragmentIntersectionFinder intersectionFinder;
protected long[] audioFragmentsDurations;
protected long[] videoFragmentsDurations;
protected AbstractManifestWriter(FragmentIntersectionFinder intersectionFinder) {
this.intersectionFinder = intersectionFinder;
}
/**
* Calculates the length of each fragment in the given <code>track</code> (as part of <code>movie</code>).
*
* @param track target of calculation
* @param movie the <code>track</code> must be part of this <code>movie</code>
* @return the duration of each fragment in track timescale
*/
public long[] calculateFragmentDurations(Track track, Movie movie) {
long[] startSamples = intersectionFinder.sampleNumbers(track, movie);
long[] durations = new long[startSamples.length];
int currentFragment = 0;
int currentSample = 1; // sync samples start with 1 !
for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
for (int max = currentSample + l2i(entry.getCount()); currentSample < max; currentSample++) {
// in this loop we go through the entry.getCount() samples starting from current sample.
// the next entry.getCount() samples have the same decoding time.
if (currentFragment != startSamples.length - 1 && currentSample == startSamples[currentFragment + 1]) {
// we are not in the last fragment && the current sample is the start sample of the next fragment
currentFragment++;
}
durations[currentFragment] += entry.getDelta();
}
}
return durations;
}
public long getBitrate(Track track) {
long bitrate = 0;
for (ByteBuffer sample : track.getSamples()) {
bitrate += sample.limit();
}
bitrate *= 8; // from bytes to bits
bitrate /= ((double) getDuration(track)) / track.getTrackMetaData().getTimescale(); // per second
return bitrate;
}
protected static long getDuration(Track track) {
long duration = 0;
for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
duration += entry.getCount() * entry.getDelta();
}
return duration;
}
protected long[] checkFragmentsAlign(long[] referenceTimes, long[] checkTimes) throws IOException {
if (referenceTimes == null || referenceTimes.length == 0) {
return checkTimes;
}
long[] referenceTimesMinusLast = new long[referenceTimes.length - 1];
System.arraycopy(referenceTimes, 0, referenceTimesMinusLast, 0, referenceTimes.length - 1);
long[] checkTimesMinusLast = new long[checkTimes.length - 1];
System.arraycopy(checkTimes, 0, checkTimesMinusLast, 0, checkTimes.length - 1);
if (!Arrays.equals(checkTimesMinusLast, referenceTimesMinusLast)) {
String log = "";
log += (referenceTimes.length);
log += ("Reference : [");
for (long l : referenceTimes) {
log += (String.format("%10d,", l));
}
log += ("]");
LOG.warning(log);
log = "";
log += (checkTimes.length);
log += ("Current : [");
for (long l : checkTimes) {
log += (String.format("%10d,", l));
}
log += ("]");
LOG.warning(log);
throw new IOException("Track does not have the same fragment borders as its predecessor.");
} else {
return checkTimes;
}
}
protected String getFormat(SampleEntry se) {
String type = se.getType();
if (type.equals("encv") || type.equals("enca") || type.equals("encv")) {
OriginalFormatBox frma = se.getBoxes(OriginalFormatBox.class, true).get(0);
type = frma.getDataFormat();
}
return type;
}
}