Java tutorial
/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.castlabs.dash.helpers; import com.coremedia.iso.boxes.Box; import com.coremedia.iso.boxes.Container; import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry; import com.googlecode.mp4parser.authoring.Sample; import com.googlecode.mp4parser.authoring.Track; import com.googlecode.mp4parser.boxes.threegpp26244.SegmentIndexBox; import com.googlecode.mp4parser.util.Path; import mpegDashSchemaMpd2011.AdaptationSetType; import mpegDashSchemaMpd2011.DescriptorType; import mpegDashSchemaMpd2011.RepresentationType; import org.apache.commons.lang.math.Fraction; import org.apache.xmlbeans.XmlOptions; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Some conversion from Track representation to Manifest specifics shared by DASH manifests of all kinds. */ public class ManifestHelper { public static String convertFramerate(double vrate) { Fraction f1 = Fraction.getFraction((int) (vrate * 1001), 1001); Fraction f2 = Fraction.getFraction((int) (vrate * 1000), 1000); double d1 = Math.abs(f1.doubleValue() - vrate); double d2 = Math.abs(f2.doubleValue() - vrate); if (d1 < d2) { return f1.getNumerator() + "/" + f1.getDenominator(); } else { return f2.getNumerator() + "/" + f2.getDenominator(); } } public static String calculateIndexRange(Container isoFile) throws IOException { SegmentIndexBox sidx = Path.getPath(isoFile, "/sidx"); long start = 0; for (Box box : isoFile.getBoxes()) { if (box == sidx) { break; } else { start += box.getSize(); } } // long start = sidx.getOffset(); getOffset works for parsed files only long end = sidx.getSize() - 1 + start; // start & end are inclusive! return String.format("%s-%s", start, end); } /** * Creates a representation and AudioChannelConfiguration if appropriate. */ public static RepresentationType createRepresentation(AdaptationSetType adaptationSet, Track track) { RepresentationType representation = adaptationSet.addNewRepresentation(); if (track.getHandler().equals("vide")) { long videoHeight = (long) track.getTrackMetaData().getHeight(); long videoWidth = (long) track.getTrackMetaData().getWidth(); double framesPerSecond = (double) (track.getSamples().size() * track.getTrackMetaData().getTimescale()) / track.getDuration(); Fraction fraction = Fraction.getFraction((int) videoWidth, (int) videoHeight).reduce(); adaptationSet.setPar("" + fraction.getNumerator() + ":" + fraction.getDenominator()); //representation.setMimeType("video/mp4"); representation.setCodecs(DashHelper.getRfc6381Codec(track.getSampleDescriptionBox().getSampleEntry())); representation.setWidth(videoWidth); representation.setHeight(videoHeight); representation.setFrameRate(convertFramerate(framesPerSecond)); representation.setSar("1:1"); // too hard to find it out. Ignoring even though it should be set according to DASH-AVC-264-v2.00-hd-mca.pdf } if (track.getHandler().equals("soun")) { AudioSampleEntry ase = (AudioSampleEntry) track.getSampleDescriptionBox().getSampleEntry(); //representation.setMimeType("audio/mp4"); representation.setCodecs(DashHelper.getRfc6381Codec(ase)); representation.setAudioSamplingRate("" + DashHelper.getAudioSamplingRate(ase)); DescriptorType audio_channel_conf = representation.addNewAudioChannelConfiguration(); DashHelper.ChannelConfiguration cc = DashHelper.getChannelConfiguration(ase); audio_channel_conf.setSchemeIdUri(cc.schemeIdUri); audio_channel_conf.setValue(cc.value); } return representation; } static Pattern REPRESENTATION_PATTERN = Pattern.compile("(\\$RepresentationID(%0[0-9]+d)?\\$)"); static Pattern NUMBER_PATTERN = Pattern.compile("(\\$Number(%0[0-9]+d)?\\$)"); static Pattern TIME_PATTERN = Pattern.compile("(\\$Time(%0[0-9]+d)?\\$)"); static Pattern BANDWIDTH_PATTERN = Pattern.compile("(\\$Bandwidth(%0[0-9]+d)?\\$)"); private static String replace(Matcher m, String rv, Object value) { while (m.find()) { if (m.group(2) != null) { rv = rv.replace(m.group(0), String.format(m.group(2), value)); } else { rv = rv.replace(m.group(0), String.valueOf(value)); } } return rv; } public static String templateReplace(String input_string, String representation_id, long number, long bandwidth, long time) { String rv = input_string; rv = rv.replace("$$", "$"); rv = replace(REPRESENTATION_PATTERN.matcher(rv), rv, representation_id); rv = replace(NUMBER_PATTERN.matcher(rv), rv, number); rv = replace(TIME_PATTERN.matcher(rv), rv, time); rv = replace(BANDWIDTH_PATTERN.matcher(rv), rv, bandwidth); return rv; } public static XmlOptions getXmlOptions() { XmlOptions xmlOptions = new XmlOptions(); //xmlOptions.setUseDefaultNamespace(); HashMap<String, String> ns = new HashMap<String, String>(); //ns.put("urn:mpeg:DASH:schema:MPD:2011", ""); ns.put("urn:mpeg:cenc:2013", "cenc"); ns.put("urn:mpeg:drmtdoday:cenc:2014", "drmtoday"); ns.put("urn:microsoft:playready", "mspr"); xmlOptions.setSaveSuggestedPrefixes(ns); xmlOptions.setSaveAggressiveNamespaces(); xmlOptions.setUseDefaultNamespace(); xmlOptions.setSavePrettyPrint(); return xmlOptions; } public static long getApproxTrackSize(Track track) { long size = 0; List<Sample> samples = track.getSamples(); int increment = samples.size() / Math.min(samples.size(), 10000); int sampleSize = 0; for (int i = 0; i < (samples.size() - increment); i += increment) { size += samples.get(i).getSize(); sampleSize++; } size = (size / sampleSize) * track.getSamples().size(); return size; } }