![JAR search and dependency download from the Maven repository](/logo.png)
com.googlecode.mp4parser.authoring.tracks.ttml.TtmlSegmenter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of isoparser Show documentation
Show all versions of isoparser Show documentation
A generic parser and writer for all ISO 14496 based files (MP4, Quicktime, DCF, PDCF, ...)
package com.googlecode.mp4parser.authoring.tracks.ttml;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import static com.googlecode.mp4parser.authoring.tracks.ttml.TtmlHelpers.getEndTime;
import static com.googlecode.mp4parser.authoring.tracks.ttml.TtmlHelpers.getStartTime;
import static com.googlecode.mp4parser.authoring.tracks.ttml.TtmlHelpers.toTime;
import static com.googlecode.mp4parser.authoring.tracks.ttml.TtmlHelpers.toTimeExpression;
public class TtmlSegmenter {
public static List split(Document doc, int splitTimeInSeconds) throws XPathExpressionException {
int splitTime = splitTimeInSeconds * 1000;
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression xp = xpath.compile("//*[name()='p']");
boolean thereIsMore;
List subDocs = new ArrayList();
do {
long segmentStartTime = subDocs.size() * splitTime;
long segmentEndTime = (subDocs.size() + 1) * splitTime;
Document d = (Document) doc.cloneNode(true);
NodeList timedNodes = (NodeList) xp.evaluate(d, XPathConstants.NODESET);
thereIsMore = false;
for (int i = 0; i < timedNodes.getLength(); i++) {
Node p = timedNodes.item(i);
long startTime = getStartTime(p);
long endTime = getEndTime(p);
//p.appendChild(d.createComment(toTimeExpression(startTime) + " -> " + toTimeExpression(endTime)));
if (startTime < segmentStartTime && endTime > segmentStartTime) {
changeTime(p, "begin", segmentStartTime - startTime);
startTime = segmentStartTime;
}
if (startTime >= segmentStartTime && startTime < segmentEndTime && endTime > segmentEndTime) {
changeTime(p, "end", segmentEndTime - endTime);
startTime = segmentStartTime;
endTime = segmentEndTime;
}
if (startTime > segmentEndTime) {
thereIsMore = true;
}
if (!(startTime >= segmentStartTime && endTime <= segmentEndTime)) {
Node parent = p.getParentNode();
parent.removeChild(p);
} else {
changeTime(p, "begin", -segmentStartTime);
changeTime(p, "end", -segmentStartTime);
}
}
trimWhitespace(d);
XPathExpression bodyXP = xpath.compile("/*[name()='tt']/*[name()='body'][1]");
Element body = (Element) bodyXP.evaluate(d, XPathConstants.NODE);
String beginTime = body.getAttribute("begin");
String endTime = body.getAttribute("end");
if (beginTime == null || "".equals(beginTime)) {
body.setAttribute("begin", toTimeExpression(segmentStartTime));
} else {
changeTime(body, "begin", segmentStartTime);
}
if (endTime == null || "".equals(endTime)) {
body.setAttribute("end", toTimeExpression(segmentEndTime));
} else {
changeTime(body, "end", segmentEndTime);
}
subDocs.add(d);
} while (thereIsMore);
return subDocs;
}
public static void changeTime(Node p, String attribute, long amount) {
if (p.getAttributes() != null && p.getAttributes().getNamedItem(attribute) != null) {
String oldValue = p.getAttributes().getNamedItem(attribute).getNodeValue();
long nuTime = toTime(oldValue) + amount;
int frames = 0;
if (oldValue.contains(".")) {
frames = -1;
} else {
// todo more precision! 44 ~= 23 frames per second.
// that should be ok for non high framerate content
// actually I'd have to get the ttp:frameRateMultiplier
// and the ttp:frameRate attribute to calculate at which frame to show the sub
frames = (int) (nuTime - (nuTime / 1000) * 1000) / 44;
}
p.getAttributes().getNamedItem(attribute).setNodeValue(toTimeExpression(nuTime, frames));
}
}
public static Document normalizeTimes(Document doc) throws XPathExpressionException {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(TtmlHelpers.NAMESPACE_CONTEXT);
XPathExpression xp = xpath.compile("//*[name()='p']");
NodeList timedNodes = (NodeList) xp.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < timedNodes.getLength(); i++) {
Node p = timedNodes.item(i);
pushDown(p);
}
for (int i = 0; i < timedNodes.getLength(); i++) {
Node p = timedNodes.item(i);
removeAfterPushDown(p, "begin");
removeAfterPushDown(p, "end");
}
return doc;
}
private static void pushDown(Node p) {
long time = 0;
Node current = p;
while ((current = current.getParentNode()) != null) {
if (current.getAttributes() != null && current.getAttributes().getNamedItem("begin") != null) {
time += toTime(current.getAttributes().getNamedItem("begin").getNodeValue());
}
}
if (p.getAttributes() != null && p.getAttributes().getNamedItem("begin") != null) {
p.getAttributes().getNamedItem("begin").setNodeValue(toTimeExpression(time + toTime(p.getAttributes().getNamedItem("begin").getNodeValue())));
}
if (p.getAttributes() != null && p.getAttributes().getNamedItem("end") != null) {
p.getAttributes().getNamedItem("end").setNodeValue(toTimeExpression(time + toTime(p.getAttributes().getNamedItem("end").getNodeValue())));
}
}
private static void removeAfterPushDown(Node p, String begin) {
Node current = p;
while ((current = current.getParentNode()) != null) {
if (current.getAttributes() != null && current.getAttributes().getNamedItem(begin) != null) {
current.getAttributes().removeNamedItem(begin);
}
}
}
public static void trimWhitespace(Node node) {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); ++i) {
Node child = children.item(i);
if (child.getNodeType() == Node.TEXT_NODE) {
child.setTextContent(child.getTextContent().trim());
}
trimWhitespace(child);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy