package railo.runtime.video;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.loader.util.Util;
import railo.runtime.config.Config;
import railo.runtime.config.ConfigImpl;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.text.xml.XMLUtil;
public class ProfileCollection {
private static VideoUtil util=VideoUtilImpl.getInstance();
private Map<String,VideoProfile> profiles;
public ProfileCollection(Config config) throws ApplicationException {
init(config,true);
}
private void init(Config config, boolean initProfiles) throws ApplicationException {
// get the video directory
Resource dir = ((ConfigImpl)config).getVideoDirectory();
// get the video.xml
Resource xml=dir.getRealResource("video.xml");
// create (if not exist) and return video xml as dom
Element video;
try {
video = getVideoXML(xml);
} catch (Exception e) {
throw new ApplicationException("can not load video xml file ["+xml+"]",Caster.toClassName(e)+":"+e.getMessage());
}
// translate form DOM to a List of VideoProfile
if(initProfiles){
try {
profiles=translateVideoXML(video);
} catch (PageException e) {
throw new ApplicationException("can not load profiles from video xml file ["+xml+"] a type is invalid",e.getMessage());
}
}
}
/**
* @return the qualities
*/
public Map<String,VideoProfile> getProfiles() {
return profiles;
}
/**
* translate form DOM to a List of VideoProfile
* @param video
* @return
* @throws PageException
*/
private static Map<String,VideoProfile> translateVideoXML(Element video) throws PageException {
Map<String,VideoProfile> profiles=new LinkedHashMap<String,VideoProfile>();
// quality
Element qd = getChildByName(video, "profiles", false);
Element[] items = getChildren(qd, "profile");
Element item;
VideoProfile vq;
String value;
for(int i=0;i<items.length;i++) {
item=items[i];
vq=new VideoProfileImpl();
// aspect-ratio
value=item.getAttribute("aspect-ratio");
if(!Util.isEmpty(value))vq.setAspectRatio(value);
// aspect-ratio
value=item.getAttribute("audio-bitrate");
if(!Util.isEmpty(value))vq.setAudioBitrate(util.toBytes(value));
// audio-samplerate
value=item.getAttribute("audio-samplerate");
if(!Util.isEmpty(value))vq.setAudioSamplerate(util.toHerz(value));
// dimension
String w = item.getAttribute("width");
String h = item.getAttribute("height");
if(!Util.isEmpty(w) && !Util.isEmpty(h)) {
vq.setDimension(Caster.toIntValue(w), Caster.toIntValue(h));
}
// framerate
value=item.getAttribute("framerate");
String value2 = item.getAttribute("fps");
if(!Util.isEmpty(value))vq.setFramerate(Caster.toDoubleValue(value));
else if(!Util.isEmpty(value2))vq.setFramerate(Caster.toDoubleValue(value2));
// video-bitrate
value=item.getAttribute("video-bitrate");
if(!Util.isEmpty(value))vq.setVideoBitrate(util.toBytes(value));
// video-bitrate-max
value=item.getAttribute("video-bitrate-max");
if(!Util.isEmpty(value))vq.setVideoBitrateMax(util.toBytes(value));
// video-bitrate-min
value=item.getAttribute("video-bitrate-min");
if(!Util.isEmpty(value))vq.setVideoBitrateMin(util.toBytes(value));
// video-bitrate-tolerance
value=item.getAttribute("video-bitrate-tolerance");
if(!Util.isEmpty(value))vq.setVideoBitrateTolerance(util.toBytes(value));
// video-codec
value=item.getAttribute("video-codec");
//print.out("video-codec:"+value);
if(!Util.isEmpty(value))vq.setVideoCodec(value);
// audio-codec
value=item.getAttribute("audio-codec");
if(!Util.isEmpty(value))vq.setAudioCodec(value);
//
value=item.getAttribute("label");
//print.out("label:"+value);
if(!Util.isEmpty(value)) {
String[] arr=toArray(value);
for(int y=0;y<arr.length;y++) {
profiles.put(arr[y].trim().toLowerCase(), vq);
}
}
}
return profiles;
}
private static Element getChildByName(Node parent, String nodeName,boolean insertBefore) {
if(parent==null) return null;
NodeList list=parent.getChildNodes();
int len=list.getLength();
for(int i=0;i<len;i++) {
Node node=list.item(i);
if(node.getNodeType()==Node.ELEMENT_NODE && node.getNodeName().equalsIgnoreCase(nodeName)) {
return (Element) node;
}
}
Element newEl = parent.getOwnerDocument().createElement(nodeName);
if(insertBefore)parent.insertBefore(newEl, parent.getFirstChild());
else parent.appendChild(newEl);
return newEl;
}
private static Element[] getChildren(Node parent, String nodeName) {
if(parent==null) return new Element[0];
NodeList list=parent.getChildNodes();
int len=list.getLength();
ArrayList rtn=new ArrayList();
for(int i=0;i<len;i++) {
Node node=list.item(i);
if(node.getNodeType()==Node.ELEMENT_NODE && node.getNodeName().equalsIgnoreCase(nodeName)) {
rtn.add(node);
}
}
return (Element[]) rtn.toArray(new Element[rtn.size()]);
}
private static String[] toArray(String str) {
StringTokenizer st=new StringTokenizer(str,",");
ArrayList list=new ArrayList();
while(st.hasMoreTokens()) {
list.add(str=st.nextToken());
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* create (if not exist) and return video xml as dom
* @param xml
* @return
* @throws IOException
* @throws SAXException
*/
private static Element getVideoXML(Resource xml) throws IOException, SAXException {
if(!xml.exists()) {
createFileFromResource("/resource/video/video.xml",xml);
}
Document doc = loadDocument(xml);
return doc.getDocumentElement();
}
public static void createFileFromResource(String path, Resource bin) throws IOException {
InputStream is=null;
OutputStream os=null;
if(bin.exists()) return;
try {
Util.copy(
is=new VideoInputImpl(null).getClass().getResourceAsStream(path),
os=bin.getOutputStream()
);
}
finally {
Util.closeEL(is);
Util.closeEL(os);
}
}
private static Document loadDocument(Resource xmlFile) throws SAXException, IOException {
InputStream is=null;
try {
return loadDocument(is=xmlFile.getInputStream());
}
finally {
Util.closeEL(is);
}
}
private static Document loadDocument(InputStream is) throws SAXException, IOException {
try{
InputSource source = new InputSource(is);
return XMLUtil.parse(source, null, false);
}
finally {
IOUtil.closeEL(is);
}
}
}