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