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.tag;
020
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.util.Iterator;
026import java.util.Random;
027
028import lucee.commons.io.res.Resource;
029import lucee.commons.io.res.util.ResourceUtil;
030import lucee.commons.lang.ClassException;
031import lucee.commons.lang.StringUtil;
032import lucee.loader.util.Util;
033import lucee.runtime.PageContext;
034import lucee.runtime.exp.ApplicationException;
035import lucee.runtime.exp.PageException;
036import lucee.runtime.ext.tag.TagSupport;
037import lucee.runtime.op.Caster;
038import lucee.runtime.type.Collection.Key;
039import lucee.runtime.type.KeyImpl;
040import lucee.runtime.type.Struct;
041import lucee.runtime.type.StructImpl;
042import lucee.runtime.type.util.KeyConstants;
043import lucee.runtime.video.ProfileCollection;
044import lucee.runtime.video.VideoExecuter;
045import lucee.runtime.video.VideoInfo;
046import lucee.runtime.video.VideoInput;
047import lucee.runtime.video.VideoInputImpl;
048import lucee.runtime.video.VideoOutput;
049import lucee.runtime.video.VideoOutputImpl;
050import lucee.runtime.video.VideoProfile;
051import lucee.runtime.video.VideoProfileImpl;
052import lucee.runtime.video.VideoUtilImpl;
053
054/**
055 * implementation of the tag Compiler
056 */
057public class Video extends TagSupport {
058
059        private static final int ACTION_CONVERT=0;
060        private static final int ACTION_INFO=1;
061        private static final int ACTION_CONCAT=2;
062        private static final int ACTION_CUT_IMAGE=4;
063        private static final int ACTION_INSTALL=8;
064        private static final int ACTION_UNINSTALL=16;
065        
066        public static final int NAMECONFLICT_UNDEFINED=0;
067        public static final int NAMECONFLICT_ERROR=1;
068        public static final int NAMECONFLICT_SKIP=2;
069        public static final int NAMECONFLICT_OVERWRITE=3;
070        public static final int NAMECONFLICT_MAKEUNIQUE=4;
071
072        public static final int EXECUTION_QUALITY=0;
073        public static final int EXECUTION_PERFORMANCE=1;
074        private static final Key SOURCE = KeyConstants._source;
075        private static final Key SOURCE1 = KeyImpl.intern("source1");
076        private static final Key SOURCE2 = KeyImpl.intern("source2");
077        private static final Key AUDIO = KeyImpl.intern("audio");
078        private static final Key VIDEO = KeyImpl.intern("video");
079        
080        private static VideoUtilImpl util=VideoUtilImpl.getInstance();
081        
082        
083        private String result="cfvideo";
084        private int action;
085        private String strAction;
086        private VideoInput source;
087        private VideoInput source1;
088        private VideoInput source2;
089        private VideoOutput destination;
090        private int nameconflict=NAMECONFLICT_UNDEFINED;
091        private String name;
092        private int width=-1;
093        private int height=-1;
094        private String strWidth;
095        private String strHeight;
096        private Struct data;
097        
098
099        private long audiosamplerate=0;
100        private long audioBitrate=0;
101        private double startTime=0;
102        private long startFrame=0;
103        private double maxTime=0;
104        private long maxFrame=0;
105        
106        private VideoProfile profile=null;
107        
108        private int aspectRatio;
109        private int framerate;
110        private long videoBitrate;
111        private long videoBitrateMin;
112        private long videoBitrateMax;
113        private long videoBitrateTolerance;
114        private String debug=null;
115        
116        private String author;
117        private String title;
118        private String comment;
119        private String copyright;
120        private String videoCodec;
121        private String audioCodec;
122        private long buffersize;
123        private int execution=EXECUTION_PERFORMANCE;
124        private static ProfileCollection _profileCollection;
125        
126        public Video(){
127                
128        }
129        
130        @Override
131        public void release() {
132                super.release();
133                result="cfvideo";
134                execution=EXECUTION_PERFORMANCE;
135                source=null;
136                source1=null;
137                source2=null;
138                destination=null;
139                nameconflict=NAMECONFLICT_UNDEFINED;
140                name=null;
141                width=-1;
142                height=-1;
143                profile=null;
144                audioBitrate=0;
145                videoCodec=null;
146                audioCodec=null;
147                
148                audiosamplerate=0;
149                aspectRatio=0;
150                framerate=0;
151                videoBitrate=0;
152                videoBitrateMin=0;
153                videoBitrateMax=0;
154                videoBitrateTolerance=0;
155                buffersize=0;
156                author=null;
157                title=null;
158                comment=null;
159                copyright=null;
160                debug=null;
161
162                maxTime=0;
163                maxFrame=0;
164                startTime=0;
165                startFrame=0;
166                strWidth=null;
167                strHeight=null;
168                data=null;
169        }
170        
171
172
173        /**
174         * @param action the action to set
175         * @throws PageException 
176         */
177        public void setAction(String action) throws PageException {
178                strAction=action;
179                action=action.toLowerCase().trim();
180        if(action.equals("concat"))                     this.action=ACTION_CONCAT; 
181        else if(action.equals("merge"))                 this.action=ACTION_CONCAT; 
182        else if(action.equals("convert"))       this.action=ACTION_CONVERT;
183        //else if(action.equals("cut"))         this.action=ACTION_CUT;
184        else if(action.equals("cut image"))     this.action=ACTION_CUT_IMAGE;
185        else if(action.equals("cutimage"))      this.action=ACTION_CUT_IMAGE;
186        else if(action.equals("cut_image"))     this.action=ACTION_CUT_IMAGE;
187        else if(action.equals("cut-image"))     this.action=ACTION_CUT_IMAGE;
188        else if(action.equals("info"))          this.action=ACTION_INFO;
189        
190        else if(action.equals("install"))               this.action=ACTION_INSTALL;
191        else if(action.equals("uninstall"))             this.action=ACTION_UNINSTALL;
192        
193        else throw doThrow("invalid value for attribute action for tag video ["+action+"], " +
194                        "valid actions are [concat, convert, cutImage, info,install,uninstall]");
195                
196        }
197
198        /**
199         * @param source the source to set
200         * @throws PageException 
201         */
202        public void setSource(String source) throws PageException {
203                this.source = new VideoInputImpl(ResourceUtil.toResourceExisting(pageContext, source));
204        }
205        
206        public void setData(Struct data){
207                this.data=data;
208        }
209
210        /**
211         * @param destination the destination to set
212         * @throws PageException 
213         */
214        public void setDestination(String destination) {
215                this.destination = new VideoOutputImpl(ResourceUtil.toResourceNotExisting(pageContext, destination));
216        }
217
218        /** set the value nameconflict
219        *  Action to take if filename is the same as that of a file in the directory.
220        * @param nameconflict value to set
221         * @throws ApplicationException 
222        **/
223        public void setNameconflict(String nameconflict) throws PageException   {
224                nameconflict=nameconflict.toLowerCase().trim();
225                if("error".equals(nameconflict))                        this.nameconflict=NAMECONFLICT_ERROR;
226                else if("skip".equals(nameconflict))            this.nameconflict=NAMECONFLICT_SKIP;
227                else if("overwrite".equals(nameconflict))       this.nameconflict=NAMECONFLICT_OVERWRITE;
228                else if("makeunique".equals(nameconflict))      this.nameconflict=NAMECONFLICT_MAKEUNIQUE;
229                else throw doThrow("invalid value for attribute nameconflict ["+nameconflict+"]",
230                                "valid values are [error,skip,overwrite,makeunique]");
231        }
232
233        public void setProfile(String strProfile) throws PageException {
234                VideoProfile p = getProfile(strProfile);
235                if(p!=null)profile=p.duplicate();
236                else throw doThrow("invalid profile defintion ["+strProfile+"], valid profiles are ["+getProfileKeyList()+"]");
237        }
238
239        public void setExecution(String execution) throws PageException {
240
241                execution=execution.toLowerCase().trim();
242                if("quality".equals(execution))                         this.execution=EXECUTION_QUALITY;
243                else if("q".equals(execution))                          this.execution=EXECUTION_QUALITY;
244                else if("performance".equals(execution))        this.execution=EXECUTION_PERFORMANCE;
245                else if("p".equals(execution))                          this.execution=EXECUTION_PERFORMANCE;
246                else throw doThrow("invalid value for attribute execution ["+execution+"]",
247                                "valid values are [quality,performance]");
248        }
249
250        public void setQuality(String strQuality) throws PageException {
251                setProfile(strQuality);
252        }
253                
254        @Override
255        public int doStartTag() throws PageException    {
256                
257                try {
258                        if(action==ACTION_CONVERT) doActionConvert();
259                        else if(action==ACTION_CONCAT) doActionConcat();
260                        else if(action==ACTION_CUT_IMAGE) doActionCutImage();
261                        else if(action==ACTION_INFO) doActionInfo();
262                        else if(action==ACTION_INSTALL) doActionInstall();
263                        else if(action==ACTION_UNINSTALL) doActionUninstall();
264                }
265                catch(Throwable t) {
266                        throw Caster.toPageException(t);
267                }
268                return SKIP_BODY;
269        }
270
271
272
273        private void doActionInstall() throws ClassException, IOException {
274                if(data==null)data=new StructImpl();
275                getVideoExecuter().install(pageContext.getConfig(),data);  
276        }
277        private void doActionUninstall() throws ClassException, IOException {
278                getVideoExecuter().uninstall(pageContext.getConfig());  
279        }
280
281        public Struct doActionInfo() throws PageException, IOException {
282                return doActionInfo(source);
283                
284        }
285        
286        private Struct doActionInfo(VideoInput source) throws PageException, IOException {
287
288                // precheck settings
289                checkFile(source,"source", true, true, false);
290                
291                //VideoConfig vc = getConfig();
292                debug(source);
293                Struct info = toStruct(getVideoExecuter().info(pageContext.getConfig(), source));
294                pageContext.setVariable(result,info);
295                return info;
296                
297        }
298
299        private VideoExecuter getVideoExecuter() throws ClassException {
300                return VideoUtilImpl.createVideoExecuter(pageContext.getConfig());
301        }
302
303
304
305        private VideoInfo getInfo(VideoInput source) throws PageException, IOException {
306
307                // precheck settings
308                checkFile(source,"source", true, true, false);
309                
310                // execute
311                return getVideoExecuter().info(pageContext.getConfig(),source);
312                //print.out(raw);
313
314                // write cfvideo                
315                //return new Info(raw,true,startTime,maxTime);  
316        }
317
318
319        private void doActionCutImage() throws PageException, IOException {
320
321                // precheck settings
322                checkFile(source,"source", true, true, false);
323                if(!checkDestination(source,destination,name,nameconflict)) return;
324                
325                // input
326                if(profile==null)profile=new VideoProfileImpl();
327                
328                // settings
329                settings(destination,profile);
330                
331                destination.setMaxFrames(1);
332                destination.setFormat("image2");
333                // execute
334                Struct info=toStruct(getVideoExecuter().convert(pageContext.getConfig(),new VideoInput[]{source},destination,profile));
335                
336                // write cfvideo
337                debug(source);
338                pageContext.setVariable(result,info);
339                
340                //setResult(raw,false);
341                
342        }
343
344
345
346        private void doActionConcat() throws PageException, IOException {
347                // precheck settings
348                checkFile(source1,"source1", true, true, false);
349                checkFile(source2,"source2", true, true, false);
350                if(!checkDestination(source1,destination,name,nameconflict)) return;
351
352                Pair s1 =toMpeg(source1);
353                Pair s2 =toMpeg(source2);
354                source = new VideoInputImpl(pageContext.getConfig().getTempDirectory().getRealResource("tmp-"+new Random().nextInt()+".mpg"));
355                try {
356                        merge(s1.res,s2.res,source.getResource());
357                        Struct sct = doActionConvert();
358                        sct.setEL(SOURCE1, s1.sct);
359                        sct.setEL(SOURCE2, s2.sct);
360                        sct.removeEL(SOURCE);
361                        
362                }
363                finally {
364                        source.getResource().delete();
365                        if(!s1.res.equals(source1.getResource()))s1.res.delete();
366                        if(!s2.res.equals(source2.getResource()))s2.res.delete();
367                }
368                
369        }
370
371
372
373        private void merge(Resource in1, Resource in2, Resource out) throws IOException {
374                InputStream is1=null;
375                InputStream is2=null;
376                OutputStream os=null;
377                try {
378                        is1=in1.getInputStream();
379                        is2=in2.getInputStream();
380                        os=out.getOutputStream();
381                }
382                catch(IOException ioe) {
383                        Util.closeEL(is1);
384                        Util.closeEL(is2);
385                        Util.closeEL(os);
386                        throw ioe;
387                }
388
389                try {
390                        copy(is1, os);
391                        copy(is2, os);
392                } 
393                finally {
394                        Util.closeEL(is1);
395                        Util.closeEL(is2);
396                        Util.closeEL(os);
397                }
398        }
399
400
401        public final static void copy(InputStream in, OutputStream out) throws IOException {
402        byte[] buffer = new byte[0xffff];
403        int len;
404        while((len = in.read(buffer)) !=-1)
405          out.write(buffer, 0, len);
406    }
407    
408
409
410
411        private Pair toMpeg(VideoInput vi) throws PageException, IOException {
412                VideoInfo info = getInfo(vi);
413                //Struct sct = _doActionInfo(vi);
414                
415                
416                if("mpeg1video".equals(info.getVideoCodec()))
417                        return new Pair(vi.getResource(),toStruct(info));
418                
419                VideoOutput tmp = new VideoOutputImpl(pageContext.getConfig().getTempDirectory().getRealResource("tmp-"+new Random().nextInt()+".mpg"));
420                try {
421                        doActionConvert(vi,tmp,null,null,NAMECONFLICT_ERROR);
422                        return new Pair(tmp.getResource(),toStruct(info));
423                }
424                catch(PageException pe) {
425                        tmp.getResource().delete();
426                        throw pe;
427                }
428                catch(IOException ioe) {
429                        tmp.getResource().delete();
430                        throw ioe;
431                }
432                
433        }
434
435
436
437        private Struct doActionConvert() throws PageException, IOException {
438                return doActionConvert(source,destination,profile,name,nameconflict);
439        }
440        private Struct doActionConvert(VideoInput source,VideoOutput destination, VideoProfile quality,String name, int nameconflict) throws PageException, IOException {
441                                
442                // precheck settings
443                checkFile(source,"source", true, true, false);
444                if(!checkDestination(source,destination,name,nameconflict)) return new StructImpl();
445                
446                // input
447                if(quality==null)quality=new VideoProfileImpl();
448                
449                // settings
450                settings(destination,quality);
451                
452                // execute
453                Struct info = toStruct(getVideoExecuter().convert(pageContext.getConfig(),new VideoInput[]{source},destination,quality));
454                
455                // write cfvideo
456                debug(source);
457                
458                pageContext.setVariable(result,info);
459                return info;
460                //return setResult(raw,false);
461        }    
462        
463
464        private void debug(VideoInput vi) throws PageException {
465                if(!StringUtil.isEmpty(debug))pageContext.setVariable(debug, vi.getCommandAsString());
466        }
467
468        private void settings(VideoOutput vo,VideoProfile vq) throws PageException, IOException {
469                defineSize(vq,new VideoInput[]{source});
470                if(audioBitrate>0)vq.setAudioBitrate(audioBitrate);
471                if(aspectRatio>0)vq.setAspectRatio(aspectRatio);
472                if(framerate>0)vq.setFramerate(framerate);
473                if(videoBitrate>0)vq.setVideoBitrate(videoBitrate);
474                if(videoBitrateMin>0)vq.setVideoBitrateMin(videoBitrateMin);
475                if(videoBitrateMax>0)vq.setVideoBitrateMax(videoBitrateMax);
476                if(videoBitrateTolerance>0)vq.setVideoBitrateTolerance(videoBitrateTolerance);
477                if(audiosamplerate>0)vq.setAudioSamplerate(audiosamplerate);
478                if(buffersize>0)vq.setBufferSize(buffersize);
479                if(execution==EXECUTION_QUALITY)vq.setPass(2);
480
481                if(!StringUtil.isEmpty(title))vo.setTitle(title);
482                if(!StringUtil.isEmpty(author))vo.setAuthor(author);
483                if(!StringUtil.isEmpty(comment))vo.setComment(comment);
484                if(!StringUtil.isEmpty(copyright))vo.setCopyright(copyright);
485                if(!StringUtil.isEmpty(videoCodec))vq.setVideoCodec(videoCodec);
486                if(!StringUtil.isEmpty(audioCodec))vq.setAudioCodec(audioCodec);
487                
488                
489                
490                if(framerate==0 && (startFrame>0 || maxTime>0)) {
491                        framerate=(int)getInfo(source).getFramerate();
492                }
493                
494                // start
495                if(startFrame>0) {
496                        if(framerate>0) startTime=(startFrame/framerate);
497                }
498                if(startTime>0)destination.setOffset(startTime);
499                
500                // max
501                if(maxTime>0) {
502                        if(framerate>0) maxFrame=(long)(maxTime*framerate);
503                }
504                if(maxTime>0)vo.setMaxFrames(maxFrame);
505                
506                // maxtime (only for cfvideo struct)
507                if(maxFrame>0 && maxTime==0) {
508                        if(framerate!=-1) maxTime=maxFrame/framerate;
509                }
510                destination.setFrameRate(framerate);
511                
512        }
513
514        private ProfileCollection getProfileCollection() throws PageException {
515                return getProfileCollection(pageContext);
516        }
517        
518        public static ProfileCollection getProfileCollection(PageContext pc) throws PageException {
519                if(_profileCollection==null) {
520                        try {
521                                _profileCollection=new ProfileCollection(pc.getConfig());
522                        } 
523                        catch (Exception e) {
524                                throw Caster.toPageException(e);
525                        }
526                }
527                return _profileCollection;
528        }
529
530        private void defineSize(VideoProfile quality, VideoInput[] sources) throws PageException {
531                if(strWidth!=null || strHeight!=null) {
532                        int[] dim = VideoUtilImpl.getInstance().calculateDimension(pageContext, sources, width, strWidth, height, strHeight);
533                        quality.setDimension(dim[0], dim[1]);
534                }
535        }
536
537        private void checkFile(VideoInput vi, String label, boolean exist, boolean canRead, boolean canWrite) throws PageException {
538                if(vi==null) {
539                        throw doThrow("attribute "+label+" is required for tag video action "+strAction);
540                }
541                checkFile(vi.getResource(), label, exist, canRead, canWrite);
542        }
543
544        private void checkFile(VideoOutput vo, String label, boolean exist, boolean canRead, boolean canWrite) throws PageException {
545                if(vo==null) {
546                        throw doThrow("attribute "+label+" is required for tag video action "+strAction);
547                }
548                checkFile(vo.getResource(), label, exist, canRead, canWrite);
549        }
550        
551        
552        private void checkFile(Resource res, String label, boolean exist, boolean canRead, boolean canWrite) throws PageException {
553                
554                if(res==null) {
555                        throw doThrow("attribute "+label+" is required for tag video action "+strAction);
556                }
557                
558                
559                if(!res.exists()) {
560                        if(exist)throw doThrow(""+label+" file does not exist");
561                }
562                else {
563                         if(!res.isFile())
564                                throw doThrow(label+" ["+res.toString()+"] is not a file");
565                else if(canRead &&!res.canRead())
566                    throw doThrow("no read access to "+label+" ["+res.toString()+"]");
567                else if(canWrite && !res.canWrite())
568                    throw doThrow("no write access to "+label+" ["+res.toString()+"]");
569                }
570        }
571        
572        private boolean checkDestination(VideoInput vi, VideoOutput destination, String name, int nameconflict) throws PageException {
573                checkFile(destination,"destination", false, false, false);
574                
575                // destination
576                if(!Util.isEmpty(name))destination.setResource(destination.getResource().getRealResource(name));
577                else if(destination.getResource().isDirectory()) {
578                        destination.setResource(destination.getResource().getRealResource(vi.getResource().getName()));
579                }
580                
581                // escape %d
582                String _name=destination.getResource().getName();
583                if(_name.indexOf("%d")!=-1) {
584                        destination.setResource(destination.getResource().getParentResource().getRealResource(_name.replaceAll("%d", "%%d")));
585                }
586                
587                
588                if(destination.getResource().exists() && nameconflict!=NAMECONFLICT_OVERWRITE) {
589                        // SKIP
590                        if(nameconflict==NAMECONFLICT_SKIP) return false;
591                        // MAKEUNIQUE
592                        else if(nameconflict==NAMECONFLICT_MAKEUNIQUE) destination.setResource(makeUnique(destination.getResource()));
593                        // ERROR
594                        else doThrow("destiniation file ["+destination.toString()+"] already exist");
595                }
596        return true;
597        }
598        
599        private Resource makeUnique(Resource res) {
600
601                String ext=getFileExtension(res);
602                String name=getFileName(res);
603                ext=(ext==null)?"":"."+ext;
604                int count=0;
605                while(res.exists()) {
606                        res=res.getParentResource().getRealResource(name+(++count)+ext);
607                }
608                return res;
609        }
610        
611        /**
612         * get file extension of a file object
613         * @param file file object
614         * @return extnesion
615         */
616        private static String getFileExtension(Resource file) {
617                String name=file.getName();
618                int index = name.lastIndexOf('.');
619                if(index==-1) return null;
620                return name.substring(index+1).trim();
621        }
622        
623        /**
624         * get file name of a file object without extension
625         * @param file file object
626         * @return name of the file 
627         */
628        private static String getFileName(Resource file) {
629                String name=file.getName();
630                int pos=name.lastIndexOf(".");
631                
632                if(pos==-1)return name;
633                return name.substring(0,pos);
634        }
635
636        private VideoProfile getProfile(String strProfile) throws PageException {
637                strProfile=strProfile.trim().toLowerCase();
638                return getProfileCollection().getProfiles().get(strProfile);
639        }
640        
641        private String getProfileKeyList() throws PageException {
642                Iterator<String> it = getProfileCollection().getProfiles().keySet().iterator();
643                StringBuffer sb=new StringBuffer();
644                boolean doDel=false;
645                while(it.hasNext()) {
646                        if(doDel)sb.append(", ");
647                        sb.append(it.next());
648                        doDel=true;
649                }
650                
651                return sb.toString();
652        }
653        
654        private PageException doThrow(String message) {
655                return doThrow(message,null);
656        }
657        
658        private PageException doThrow(String message, String detail) {
659                if(detail==null)return new ApplicationException(message);
660                return new ApplicationException(message,detail);
661        }
662        
663
664
665
666
667        /**
668         * @param width the width to set
669         */
670        public void setWidth(String strWidth) {
671                this.width = Caster.toIntValue(strWidth,-1);
672                this.strWidth = strWidth;
673        }
674
675        /**
676         * @param height the height to set
677         */
678        public void setHeight(String strHeight) {
679                this.height = Caster.toIntValue(strHeight,-1);
680                this.strHeight = strHeight;
681        }
682
683        /**
684         * @param audioBitrate the audioBitrate to set
685         * @throws PageException 
686         */
687        public void setAudiobitrate(String audioBitrate) throws PageException {
688                this.audioBitrate = util.toBytes(audioBitrate);
689        }
690
691        /**
692         * @param aspectRatio the aspectRatio to set
693         * @throws PageException 
694         */
695        public void setAspectratio(String strAspectRatio) throws PageException {
696                strAspectRatio=strAspectRatio.trim().toLowerCase();
697                if("16:9".equals(strAspectRatio)) aspectRatio=VideoProfile.ASPECT_RATIO_16_9;
698                else if("4:3".equals(strAspectRatio)) aspectRatio=VideoProfile.ASPECT_RATIO_4_3;
699                else throw doThrow("invalid aspect ratio definition ["+strAspectRatio+"], valid values are [16:9, 4:3]");
700        }
701
702        /**
703         * @param framerate the framerate to set
704         */
705        public void setFramerate(double framerate) {
706                setFps(framerate);
707        }
708        public void setFps(double framerate) {
709                this.framerate = (int) framerate;
710        }
711
712        /**
713         * @param videoBitrate the videoBitrate to set
714         * @throws PageException 
715         */
716        public void setVideobitrate(String videoBitrate) throws PageException {
717                this.videoBitrate = util.toBytes(videoBitrate);
718        }
719
720        /**
721         * @param videoBitrateMin the videoBitrateMin to set
722         * @throws PageException 
723         */
724        public void setVideobitratemin(String videoBitrateMin) throws PageException {
725                this.videoBitrateMin = util.toBytes(videoBitrateMin);
726        }
727
728        /**
729         * @param videoBitrateMax the videoBitrateMax to set
730         * @throws PageException 
731         */
732        public void setVideobitratemax(String videoBitrateMax) throws PageException {
733                this.videoBitrateMax = util.toBytes(videoBitrateMax);
734        }
735
736        /**
737         * @param videoBitrateTolerance the videoBitrateTolerance to set
738         * @throws PageException 
739         */
740        public void setVideobitratetolerance(String videoBitrateTolerance) throws PageException {
741                this.videoBitrateTolerance = util.toBytes(videoBitrateTolerance);
742        }
743
744        /**
745         * @param author the author to set
746         */
747        public void setAuthor(String author) {
748                this.author = author;
749        }
750
751        /**
752         * @param title the title to set
753         */
754        public void setTitle(String title) {
755                this.title = title;
756        }
757
758        /**
759         * @param comment the comment to set
760         */
761        public void setComment(String comment) {
762                this.comment = comment;
763        }
764
765        /**
766         * @param copyright the copyright to set
767         */
768        public void setCopyright(String copyright) {
769                this.copyright = copyright;
770        }
771
772        /**
773         * @param max the maxFrames to set
774         * @throws PageException 
775         */
776        public void setMax(String strMax) throws PageException {
777                strMax=strMax.trim().toLowerCase();
778                if(strMax.endsWith("f"))                        this.maxFrame=Caster.toLongValue(strMax.substring(0,strMax.length()-1));
779                else if(strMax.endsWith("ms"))  this.maxTime=Caster.toDoubleValue(strMax.substring(0,strMax.length()-2))/1000F;
780                else if(strMax.endsWith("s"))           this.maxTime=Caster.toDoubleValue(strMax.substring(0,strMax.length()-1));
781                else setStart(strMax+" ms");
782        }
783
784        /**
785         * @param result the result to set
786         */
787        public void setResult(String result) {
788                this.result = result;
789        }
790
791
792
793        /**
794         * @param source1 the source1 to set
795         * @throws PageException 
796         */
797        public void setSource1(String source1) throws PageException {
798                this.source1 = new VideoInputImpl(ResourceUtil.toResourceExisting(pageContext, source1));
799        }
800
801
802
803        /**
804         * @param source2 the source2 to set
805         * @throws PageException 
806         */
807        public void setSource2(String source2) throws PageException {
808                this.source2 = new VideoInputImpl(ResourceUtil.toResourceExisting(pageContext, source2));
809        }
810
811
812
813        /**
814         * @param strStart the position to set
815         * @throws PageException 
816         */
817        public void setStart(String strStart) throws PageException {
818                strStart=strStart.trim().toLowerCase();
819                if(strStart.endsWith("f"))                      this.startFrame=Caster.toLongValue(strStart.substring(0,strStart.length()-1));
820                else if(strStart.endsWith("ms"))        this.startTime=Caster.toDoubleValue(strStart.substring(0,strStart.length()-2))/1000F;
821                else if(strStart.endsWith("s"))         this.startTime=Caster.toDoubleValue(strStart.substring(0,strStart.length()-1));
822                else setStart(strStart+" ms");
823        }
824
825        /**
826         * @param videoCodec the videoCodec to set
827         */
828        public void setVideocodec(String videoCodec) {
829                this.videoCodec = videoCodec;
830        }
831        public void setAudiocodec(String audioCodec) {
832                this.audioCodec = audioCodec;
833        }
834        
835        class Pair {
836                Resource res;
837                Struct sct;
838                public Pair(Resource res, Struct sct) {
839                        this.res = res;
840                        this.sct = sct;
841                }
842        }
843
844        /**
845         * @param audiosamplerate the audiosamplerate to set
846         * @throws PageException 
847         */
848        public void setAudiosamplerate(String sAudiosamplerate) throws PageException {
849                this.audiosamplerate = util.toHerz(sAudiosamplerate);
850        }
851
852        public static void checkRestriction() {
853                
854        }
855        
856        /**
857         * @param debug the debug to set
858         */
859        public void setDebug(String debug) {
860                this.debug = debug;
861        }
862
863        /**
864         * @param buffersize the buffersize to set
865         */
866        public void setBuffersize(double buffersize) {
867                this.buffersize = (long) buffersize;
868        }
869        
870
871        public Struct toStruct(VideoInfo[] infos) {
872                Struct sct=new StructImpl();
873                sct.setEL(KeyConstants._source, toStruct(infos[0]));
874                sct.setEL(KeyConstants._destination, toStruct(infos[1]));
875                return sct;
876        }
877        
878        private Struct toStruct(VideoInfo info) {
879                
880                Struct sct=info.toStruct();
881                
882                // audio
883                Struct audio=Caster.toStruct(sct.get(AUDIO,null),null);
884                if(audio==null) {
885                        audio=new StructImpl();
886                        sct.setEL(AUDIO, audio);
887                }
888                
889                // video
890                Struct video=Caster.toStruct(sct.get(VIDEO,null),null);
891                if(video==null) {
892                        video=new StructImpl();
893                        sct.setEL(VIDEO, video);
894                }
895                
896                // Audio
897                audio.setEL("channels", info.getAudioChannels());
898                audio.setEL(KeyConstants._codec, info.getAudioCodec());
899                if(info.getAudioBitrate()!=-1)audio.setEL("bitrate", new Double(info.getAudioBitrate()));
900                if(info.getAudioSamplerate()!=-1)audio.setEL("samplerate", new Double(info.getAudioSamplerate()));
901                
902                // Video
903                video.setEL(KeyConstants._codec, info.getVideoCodec());
904                video.setEL(KeyConstants._format, info.getVideoFormat());
905                if(info.getVideoBitrate()!=-1)video.setEL("bitrate", new Double(info.getVideoBitrate()));
906                if(info.getFramerate()!=-1)video.setEL("framerate", new Double(info.getFramerate()));
907                
908                // Allgemein
909                if(info.getDuration()!=-1)sct.setEL("duration", new Double(info.getDuration()));
910                if(info.getHeight()!=-1)sct.setEL(KeyConstants._height, new Double(info.getHeight()));
911                if(info.getWidth()!=-1)sct.setEL(KeyConstants._width, new Double(info.getWidth()));
912                
913                
914                
915                return sct;
916        }
917}