![JAR search and dependency download from the Maven repository](/logo.png)
org.mp4parser.muxer.tracks.ttml.TtmlSegmenter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of muxer Show documentation
Show all versions of muxer Show documentation
This package has a focus on file operation. It can read A/V data from Random Access Datasources
package org.mp4parser.muxer.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.xpath.*;
import java.util.ArrayList;
import java.util.List;
import static org.mp4parser.muxer.tracks.ttml.TtmlHelpers.*;
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