001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.video; 020 021import java.util.Map; 022 023import lucee.commons.io.res.Resource; 024import lucee.commons.io.res.type.file.FileResource; 025import lucee.commons.io.res.type.http.HTTPResource; 026import lucee.commons.lang.ClassException; 027import lucee.commons.lang.ClassUtil; 028import lucee.commons.lang.StringUtil; 029import lucee.runtime.PageContext; 030import lucee.runtime.config.Config; 031import lucee.runtime.exp.ApplicationException; 032import lucee.runtime.exp.ExpressionException; 033import lucee.runtime.exp.PageException; 034import lucee.runtime.functions.string.Hash; 035import lucee.runtime.op.Caster; 036 037import org.apache.commons.collections.map.ReferenceMap; 038 039public class VideoUtilImpl implements VideoUtil { 040 041 042 private static Map sizes=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT); 043 private static VideoUtilImpl instance=new VideoUtilImpl(); 044 045 private VideoUtilImpl(){ } 046 047 public static VideoUtilImpl getInstance() { 048 return instance; 049 } 050 051 /** 052 * @see lucee.runtime.video.VideoUtil#createVideoInput(lucee.commons.io.res.Resource) 053 */ 054 public VideoInput createVideoInput(Resource input) { 055 return new VideoInputImpl(input); 056 } 057 058 /** 059 * @see lucee.runtime.video.VideoUtil#createVideoOutput(lucee.commons.io.res.Resource) 060 */ 061 public VideoOutput createVideoOutput(Resource output) { 062 return new VideoOutputImpl(output); 063 } 064 065 /** 066 * @see lucee.runtime.video.VideoUtil#createVideoProfile() 067 */ 068 public VideoProfile createVideoProfile() { 069 return new VideoProfileImpl(); 070 } 071 072 073 public long toBytes(String byt) throws PageException { 074 byt=byt.trim().toLowerCase(); 075 if(byt.endsWith("kb/s") || byt.endsWith("kbps")) { 076 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-4).trim())*1024); 077 } 078 if(byt.endsWith("mb/s") || byt.endsWith("mbps")) { 079 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-4).trim())*1024*1024); 080 } 081 if(byt.endsWith("gb/s") || byt.endsWith("gbps")) { 082 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-4).trim())*1024*1024*1024); 083 } 084 if(byt.endsWith("b/s") || byt.endsWith("bps")) { 085 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-3).trim())); 086 } 087 088 if(byt.endsWith("kbit/s")) { 089 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-6).trim())*1024); 090 } 091 if(byt.endsWith("mbit/s")) { 092 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-6).trim())*1024*1024); 093 } 094 if(byt.endsWith("gbit/s")) { 095 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-6).trim())*1024*1024*1024); 096 } 097 if(byt.endsWith("bit/s")) { 098 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-5).trim())); 099 } 100 101 102 if(byt.endsWith("kb")) { 103 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-2).trim())*1024); 104 } 105 if(byt.endsWith("mb")) { 106 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-2).trim())*1024*1024); 107 } 108 if(byt.endsWith("gb")) { 109 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-2).trim())*1024*1024*1024); 110 } 111 112 if(byt.endsWith("g")) { 113 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-1).trim())*1024*1024*1024); 114 } 115 if(byt.endsWith("m")) { 116 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-1).trim())*1024*1024); 117 } 118 if(byt.endsWith("k")) { 119 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-1).trim())*1024); 120 } 121 if(byt.endsWith("b")) { 122 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-1).trim())); 123 } 124 return Caster.toLongValue(byt); 125 } 126 127 public long toHerz(String byt) throws PageException { 128 byt=byt.trim().toLowerCase(); 129 if(byt.endsWith("mhz")) { 130 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-3).trim())*1000*1000); 131 } 132 if(byt.endsWith("khz")) { 133 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-3).trim())*1000); 134 } 135 if(byt.endsWith("hz")) { 136 return (long)(Caster.toDoubleValue(byt.substring(0,byt.length()-2).trim())); 137 } 138 return Caster.toLongValue(byt); 139 } 140 141 public long toMillis(String time) throws PageException { 142 int last=0,index=time.indexOf(':'); 143 long hour=Caster.toIntValue(time.substring(last,index).trim()); 144 last=index+1; 145 146 index=time.indexOf(':',last); 147 long minute=Caster.toIntValue(time.substring(last,index).trim()); 148 149 double seconds=Caster.toDoubleValue(time.substring(index+1).trim()); 150 return (hour*60L*60L*1000L)+(minute*60L*1000L)+((int)(seconds*1000F)); 151 } 152 153 public static VideoExecuter createVideoExecuter(Config config) throws ClassException { 154 Class clazz = config.getVideoExecuterClass(); 155 return (VideoExecuter) ClassUtil.loadInstance(clazz); 156 } 157 158 public int[] calculateDimension(PageContext pc,VideoInput[] sources,int width, String strWidth,int height, String strHeight) throws PageException { 159 int[] rtn; 160 161 if(width!=-1 && height!=-1) { 162 return new int[]{width,height}; 163 } 164 165 // video component not installed 166 try { 167 if(VideoUtilImpl.createVideoExecuter(pc.getConfig()) instanceof VideoExecuterNotSupported){ 168 throw new ApplicationException("attributes width/height are required when no video analyser is installed"); 169 } 170 } catch (ClassException e) { 171 172 } 173 174 175 VideoInput source; 176 177 // hash 178 StringBuffer sb=new StringBuffer(strHeight+"-"+strWidth); 179 for(int i=0;i<sources.length;i++) { 180 sb.append(sources[i].getResource().toString()); 181 } 182 183 // get from casche 184 String key = Hash.call(pc, sb.toString()); 185 186 int[] ci=(int[]) sizes.get(key); 187 if(ci!=null) { 188 return ci; 189 } 190 // getSize 191 int w=0,h=0; 192 try { 193 for(int i=0;i<sources.length;i++) { 194 source = sources[i]; 195 checkResource(source.getResource()); 196 197 198 VideoInfo info = VideoUtilImpl.createVideoExecuter(pc.getConfig()).info(pc.getConfig(),source); 199 200 if(w<info.getWidth()) { 201 h=info.getHeight(); 202 w=info.getWidth(); 203 } 204 205 206 } 207 } 208 catch(Exception ve) { 209 throw Caster.toPageException(ve); 210 } 211 212 // calculate only height 213 if(width!=-1) { 214 height=calculateSingle(w,width,strHeight,h); 215 } 216 // calculate only height 217 else if(height!=-1) { 218 width=calculateSingle(h,height,strWidth,w); 219 } 220 else { 221 width=procent2pixel(strWidth,w); 222 height=procent2pixel(strHeight,h); 223 if(width!=-1 && height!=-1) {} 224 else if(width==-1 && height==-1) { 225 width=w; 226 height=h; 227 } 228 else if(width!=-1) 229 height=calucalteFromOther(h,w,width); 230 else 231 width=calucalteFromOther(w,h,height); 232 233 234 } 235 sizes.put(key, rtn=new int[]{width,height}); 236 return rtn; 237 } 238 239 private static int procent2pixel(String str, int source) throws ExpressionException { 240 if(!StringUtil.isEmpty(str)) { 241 if(StringUtil.endsWith(str, '%')) { 242 str=str.substring(0,str.length()-1).trim(); 243 double procent = Caster.toDoubleValue(str); 244 if(procent<0 ) 245 throw new ExpressionException("procent has to be positive number (now "+str+")"); 246 return (int)(source*(procent/100D)); 247 } 248 return Caster.toIntValue(str); 249 } 250 return -1; 251 } 252 253 private static int calculateSingle(int srcOther,int destOther, String strDim, int srcDim) throws ExpressionException { 254 int res = procent2pixel(strDim, srcDim); 255 if(res!=-1) return res; 256 return calucalteFromOther(srcDim,srcOther,destOther);//(int)(Caster.toDoubleValue(srcDim)*Caster.toDoubleValue(destOther)/Caster.toDoubleValue(srcOther)); 257 } 258 259 private static int calucalteFromOther(int srcDim,int srcOther,int destOther) { 260 return (int)(Caster.toDoubleValue(srcDim)*Caster.toDoubleValue(destOther)/Caster.toDoubleValue(srcOther)); 261 } 262 263 264 private static void checkResource(Resource resource) throws ApplicationException { 265 if(resource instanceof FileResource)return; 266 if(resource instanceof HTTPResource) 267 throw new ApplicationException("attribute width and height are required when external sources are invoked"); 268 269 throw new ApplicationException("the resource type ["+resource.getResourceProvider().getScheme()+"] is not supported"); 270 } 271}