-
Notifications
You must be signed in to change notification settings - Fork 10
/
commands.xml
1816 lines (1605 loc) · 93.3 KB
/
commands.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0"?>
<!--
Copyright (c) 2009-2011 Chris Marrin ([email protected])
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Video Monkey nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
-->
<!--
This file describes the actions to be taken when the VideoMonkey GUI is manipulated. There are two main purposes: setting information that will be displayed in the Info Panel for the output file, and constructing a recipe for the encoding. JavaScript functions here are also provided to parse the output of the various encoding tools and pass back progress bar information.
For each input file, information about it (size, bitrate, frame rate, etc.) is made available. When any change is made to the GUI (selecting a menu item, sliding a slider, checking a box, etc.) this file performs the actions shown below for each file in the list.
File Syntax
===========
The Command file contains an outer <videomonkey> element with one of each children:
<default_device> - parameters used by any device when not overridden, with children:
<quality> - set of stops for quality slider, with children:
<quality_stop> - one quality stop, with attributes:
title - the title of the tick mark
<performance> - values for performance menu, with children:
<performance_item> - one item in menu, with attributes and children:
title - title of this item in menu
<param>, <command>, <script> - see below
<param>, <command>, <script> - see below
<devices> - List of devices in device menu, with children:
<device_group> - A grouping of devices. Each groups has a title and groups are separated by a line,
with attributes and children:
title - title for this group
<common_device> - features common to all devices in this group, with same children as <default_device>
<device> - device in this group, with same children as <default_device> and additional attributes and children:
title - title for this device
icon - name of the icon image to use for this device
enabled - whether or not this device is enabled in the device list (true | false)
<checkbox> - this describes a checkbox, with attributes and children:
which - which checkbox (0-n)
title - title on the checkbox
enabled - whether or not this checkbox is enabled (true | false)
<checked_item> - parameters used when this checkbox is checked, with children:
<param>, <command>, <script> - see below
<unchecked_item> - parameters used when this checkbox is not checked, with children:
<param>, <command>, <script> - see below
<menu> - this describes a menu, with children:
which - which menu (0-n)
title - title on the menu
enabled - whether or not this menu is enabled (true | false)
<menu_item> - one entry in the menu, with attributes and children:
title - title of this menu item
<param>, <command>, <script> - see below
<radio_group> - encloses a group of menu items to treat as radio buttons
<menu_item> - same as above
<checkbox> - menu item that can be checked or unchecked
<checked_item> - same as above
<unchecked_item> - same as above
<submenu>
title - title of this submenu
<menu_item> - same as above
<param>, <command>, <script> - see below
<separator> - separation line between items
<param>, <command>, <script> - see below
<script> element
================
Wherever a <script> element is allowed, there can be 0 or more. All scripts are concatenated and executed as one. Scripts have access to the normal JavaScript objects (Object, String, Array, etc.). In addition, there is a log() function which takes 0 or more parameters, each of which is converted to a string, concatenated and output to the console. After all strings of a log() function are printed, a newline is printed. Log entries are prefixed for identification. A 'params' Object is also provided, with properties set as shown below.
<param> element
===============
Wherever a <param> element is allowed, there can be 0 or more. Each element adds a property to the 'params' Object whose property name is obtained from the 'id' attribute of the <params> element and whose property value is obtained from the 'value' attribute.
<command> element
=================
Wherever a <command> element is allowed, there can be 0 or more. Commands are just like params except that the property value is the contents of the element, rather than a 'value' attribute. All newline characters are stripped from the content string, as are any leading or trailing whitespace characters.
<performance> element
=================
The <performance> element has 0 or more <performance_item> elements whose 'title' attributes are presented to the user in the 'Encoding speed:' menu. Each <performance_item> can contain <script>, <param> and <command> elements that are executed when that item is selected.
<quality> element
=================
The <quality> element has 0 or more <quality_stop> elements whose 'title' attributes are presented to the user as the tick marks of the 'Quality' slider. Each <quality_stop> can contain <script>, <param> and <command> elements that are executed when the slider is closer to that tick mark than any other.
<checkbox> element
=================
The <checkbox> element's 'title' attribute is presented to the user as the checkbox indicated by the 'which' attribute (see below). This element has 0 or more <checked_item> and <unchecked_item> elements whose <script>, <param> and <command> elements are executed when the checkbox is checked or unchecked, as appropriate. The checkbox element can also appear inside a <menu> element, where it is used as a check menu item. In this case the 'which' attribute is ignored.
<menu> element
=================
The <menu> element's 'title' attribute is presented to the user as the menu indicated by the 'which' attribute (see below). This element has 0 or more <menu_item> elements whose <script>, <param> and <command> elements are executed when that menu item is selected. In some cases the menu is presented as a set of radio buttons. In this case, each menu_item is a radio button and when selected, it's <script>, <param> and <command> elements are executed. A <menu> element can inside another menu element, making it a submenu. In this case the 'which' attribute is ignored.
<radio_group>
=============
The <radio_group> element can appear inside a <menu> element (top level or submenu). Inside the <radio_group> can appear 0 or more <menu_item> elements, each of which becomes on radio item of the group. When a menu_item is selected, its <script>, <param> and <command> elements are executed.
GUI layout
=================
The layout of GUI is determined by the 'which' attributes of the <menu> and <checkbox> elements. There are 4 layouts:
a) 0 to 3 checkboxes and no menus
b) 0 to 2 checkboxes, an optional set of radio buttons with 2 buttons, and an optional pulldown menu
c) A custom layout for controlling all encoding paramerters
d) A layout designed for DVD authoring (currently not implemented).
Radio buttons for layout (a) and (b) are selected by setting the 'which' attribute to 0, and a pulldown menu is specified with a 'which' attribute of 1. If a menu with a 'which' attribute of 0 or 1 is set, layout (b) is selected. Otherwise layout (a) is selected. In either layout, checkboxes are laid out right to left, e.g., a checkbox with a 'which' attribute of 0 is the right-most in both layouts.
Execution
=========
The workhorse elements are <param>, <command> and <script>. These contain the instructions which ultimately lead to a recipe to use for the encoding task. Params and commands are added to the JavaScript 'params' object in one pass, as long as they are contained in elements which are selected. And then the scripts are executed in a separate pass, as long as their elements are selected. So even later defined params and commands are accessible to earlier scripts. Scripts are executed according to the elements which contain them in the following order:
1) <default_device>
2) selected <performance_item> from <default_device>
3) <common_device> for selected <device>
4) selected <performance_item> from <common_device> for selected <device>
5) selected <device>
6) selected <performance_item> from selected <device>
7) <checked_item> or <unchecked_item> entry from each <checkbox> in selected <device>
8) selected <menu_item> entry from each <menu> in selected <device>
The result of this script execution is the output params (see below) being set for display in the Output Info Panel, and a string in 'params.recipe' which is the recipe to be executed. See below for recipe syntax. These scripts are executed when any UI control is changed. This includes the slider, which executes the scripts for each move. The script is executed in turn for each file selected for encoding. This pass of script execution is to fill in the file list entries. When encoding is started, the scripts are executed again for the currently encoding file and the recipe is used to start the encoding. Once encoding is finished, the scripts are executed for the next file, and so on.
Javascript Params
=================
Each time scripts execute, a number of parameters are preloaded into the 'params' property. These are:
Param Name Value
========== =====
app_resource_path Path to application resources
input_file Current input file path
output_file Current output file path
tmp_audio_file Path to a temp file to which audio can be saved
input_format Container format of input file
input_duration Duration of input video
input_video_width Width, in pixels, of the input file
input_video_height Height, in pixels, of the input file
input_frame_rate Frame rate, in fps, of the input file
input_video_bitrate Bitrate of the video in the input file
input_video_aspect Video aspect ratio (may be different from width/height for non-square pixels)
input_video_codec Name of the video codec of the input file
input_video_index Video stream index in the file (used by the -map attr)
input_audio_index Audio stream index in the file (used by the -map attr)
audio_offset Offset to apply to audio, in seconds.
video_offset Offset to apply to video, in seconds.
has_audio "true" if the input file contains an audio track
duration Duration of video, in seconds
quality The current setting of the quality slider (0-1 between tick marks)
quality_stop Which tick mark is currently to the left of the slider (0 to #ticks-1)
title Title of the currently selected device
limit_output_params "true" if output params should be limited to be no larger than input
num_cpus Number of CPUs to use during encoding
After executing all the scripts (see Execution) the system expects the following properties to be set in the 'params' property:
Param Name Value
========== =====
recipe Recipe to use for the current encoding
output_video_width Width, in pixels, of the output file
output_video_height Height, in pixels, of the output file
output_video_bitrate Approximate bitrate of the output video
output_format_name Displayed format of the container
output_video_codec_name Displayed video codec
output_video_profile_name Displayed profile of the video
output_video_level_name Displayed level of this video
output_video_frame_rate Framerate of the output file
output_video_aspect_ratio Aspect ratio of the output file
output_audio_codec_name Displayed audio codec
output_audio_bitrate Audio bitrate
output_audio_sample_rate Sample rate of audio
output_audio_channels Number of channels of audio
output_audio_quality A string indicating the audio quality of the output file (usually "low", "medium" or "high")
processResponse Global function that handles lines of stderr output from the executing commands (Do not change)
processResponseCallbacks An Array of functions called by processResponse()
processResponseProgress The current progress of the currently executing command, from 0 to 1
processResponseMessage String to be output to the error console.
The following are generated during script execution and are used in the generation of the recipe:
Param Name Value
========== =====
ffmpeg_video_aspect_x numerator of the -aspect param
ffmpeg_video_aspect_y denominator of the -aspect param
ffmpeg_x264_preset x264 preset param, including -vpre (if output codec is x264, empty otherwise)
ffmpeg_x264_pass1_preset x264 preset param for pass1, including -vpre (if output codec is x264 and 2 pass, empty otherwise)
ffmpeg_option_target
ffmpeg_option_padleft
ffmpeg_option_padright
ffmpeg_option_padtop
ffmpeg_option_padbottom
ffmpeg_option_vcodec
ffmpeg_option_acodec
ffmpeg_option_pix_fmt
ffmpeg_option_vtag currently only set to DX50 in AVI
ffmpeg_option_g
ffmpeg_option_maxrate
ffmpeg_option_qmin
ffmpeg_option_bf
ffmpeg_extra_options
apple_tv_format_limit True if output frame size is limited to 960x540 @ 30hz or 1024x720 @ 24hz (1st gen Apple TV)
The recipe is used for the actual encoding, the others output values are used to update the file entries, and the
processResponse values are used to process stderr responses from the executing command.
processResponse
===============
The default script creates a processResponse function, which should not be changed by specific device scripts. It has
the form:
function processResponse(command, response)
where command is the name of the executing command and response is the complete line that was sent to stderr.
When a response is received, processResponse sends the response to each function in the processResponseCallbacks
Array. Each function in this array has the same form as processResponse. The callback performs any processing
required and then sets 2 param values, processResponseProgress and processResponseMessage. The callback must
return true if the response was processed and false otherwise. If false, the next function in the Array is called.
Recipes
=======
A recipe is essentially a shell script to be passed to /bin/sh. A param (from the global 'params' object) can be included with a '$' followed by the property name. For instance if there were a 'params.foo' property with the value "very nice", then the recipe "This is a $foo command" would translate to "This is a very nice command". To include a literal '$' simply use two consecutively ('$$').
A property name is anything from the character after the '$' to the next whitespace character. Or you can use parantheses around the property name to concatenate with non-whitespace characters. For instance "This is the $(foo)st command" would translate to "This is the very nicest command".
FFMpeg Parameters
=================
Useful URLs:
http://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
http://www.webupd8.org/2009/08/ffmpeg-cheat-sheet-19-best-practices.html
http://rob.opendot.cl/index.php/useful-stuff/h264-profiles-and-levels/
These parameters are always included and never changed by these scripts:
========================================================================
-pass (1 or 2) identifes pass for 2 pass encoding
-threads Number of threads used. Always set to $num_cpus
-y Overwrite output files (always included)
-i Precedes input file
ffmpeg ffmpeg command path
DTD
===
<!DOCTYPE videomonkey [
<!ELEMENT videomonkey (default_device|devices)*>
<!ELEMENT script (#PCDATA)>
<!ELEMENT param EMPTY>
<!ATTLIST param id CDATA "">
<!ATTLIST param value CDATA "">
<!ELEMENT default_device (quality|performance|script|param|command)*>
<!ELEMENT common_device (quality|performance|script|param|command)*>
<!ELEMENT devices (device_group*)>
<!ELEMENT command (#PCDATA)>
<!ATTLIST command id CDATA "">
<!ELEMENT quality (quality_stop*)>
<!ELEMENT quality_stop EMPTY>
<!ATTLIST quality_stop title CDATA "">
<!ELEMENT performance (performance_item*)>
<!ELEMENT performance_item (script|param|command)*>
<!ATTLIST performance_item title CDATA "">
<!ELEMENT device_group (common_device?,device*)>
<!ATTLIST device_group title CDATA "">
<!ELEMENT device (quality|performance|script|param|command|checkbox|menu)*>
<!ATTLIST device title CDATA "">
<!ATTLIST device icon CDATA "">
<!ATTLIST device enabled CDATA "">
<!ELEMENT checkbox (checked_item|unchecked_item)*>
<!ATTLIST checkbox which CDATA "">
<!ATTLIST checkbox title CDATA "">
<!ATTLIST checkbox enabled CDATA "">
<!ELEMENT checked_item (script|param|command)*>
<!ELEMENT unchecked_item (script|param|command)*>
<!ELEMENT menu (menu_item|radio_group|checkbox|menu|separator*)>
<!ATTLIST menu which CDATA "">
<!ATTLIST menu title CDATA "">
<!ATTLIST menu enabled CDATA "">
<!ELEMENT menu_item (script|param|command)*>
<!ATTLIST menu_item title CDATA "">
<!ELEMENT radio_group (menu_item*)>
<!ATTLIST radio_group title CDATA "">
<!ELEMENT separator EMPTY>
]>
-->
<videomonkey>
<default_device>
<!-- Init params used -->
<param id="ffmpeg_option_target" value="" />
<param id="ffmpeg_option_padleft" value="" />
<param id="ffmpeg_option_padright" value="" />
<param id="ffmpeg_option_padtop" value="" />
<param id="ffmpeg_option_padbottom" value="" />
<param id="ffmpeg_option_vtag" value="" />
<param id="ffmpeg_option_g" value="" />
<param id="ffmpeg_option_maxrate" value="" />
<param id="ffmpeg_option_qmin" value="" />
<param id="ffmpeg_option_bf" value="" />
<param id="output_video_bitrate" value="0" />
<param id="output_video_profile_name" value="" />
<param id="output_video_level_name" value="" />
<param id="ffmpeg_vpre_pass1" value="" />
<param id="ffmpeg_vpre" value="" />
<param id="ffmpeg_vpre_profile" value="" />
<param id="ffmpeg_video_aspect_x" value="0" />
<param id="ffmpeg_video_aspect_y" value="0" />
<param id="output_audio_sample_rate" value="0" />
<!-- Advanced menu items -->
<param id="advanced_audio_codec" value="MP3,AAC,WMA,AC3,MP2,PCM" />
<param id="advanced_audio_channels" value="1,2" />
<param id="advanced_audio_bitrate" value="16000,32000,128000,160000,192000,320000,1400000" />
<param id="advanced_audio_sample_rate" value="8000,11025,16000,22050,32000,44056,44100,47250,48000,88200,96000" />
<param id="advanced_video_codec" value="H.264,MPEG-4,WMV,FLV,MPEG-1,MPEG-2,Digital Video" />
<param id="advanced_video_profile" value="baseline,main" />
<!-- Apps -->
<command id="ffmpeg">
"$(app_resource_path)/bin/ffmpeg"
</command>
<!-- Default params (sometimes overridden) -->
<param id="output_video_profile_name" value="baseline" />
<!-- Composite options -->
<command id="ffmpeg_single_pass_options">
$ffmpeg_vpre $ffmpeg_vpre_profile
</command>
<command id="ffmpeg_pass1_options">
-pass 1 $ffmpeg_vpre_pass1 $ffmpeg_vpre_profile
</command>
<command id="ffmpeg_pass2_options">
-pass 2 $ffmpeg_vpre $ffmpeg_vpre_profile
</command>
<!-- Raw encoding commands -->
<command id="ffmpeg_normal_av">
$ffmpeg -threads $num_cpus -y -i "$input_file"
</command>
<command id="ffmpeg_normal_av_offset">
$ffmpeg -threads $num_cpus -y -itsoffset $video_offset -i "$input_file"
-itsoffset $audio_offset -i "$input_file" -map 0:$(input_video_index) -map 1:$(input_audio_index)
</command>
<command id="ffmpeg_normal_v">
$ffmpeg -threads $num_cpus -y -i "$input_file"
</command>
<command id="yuv_to_ffmpeg_av">
$ffmpeg -threads $num_cpus -y -i - -i "$tmp_audio_file"
</command>
<command id="yuv_to_ffmpeg_av_offset">
$ffmpeg -threads $num_cpus -y -itsoffset $video_offset -i -
-itsoffset $audio_offset -i "$tmp_audio_file" -map 0:$(input_video_index) -map 1:$(input_audio_index)
</command>
<command id="yuv_to_ffmpeg_v">
$ffmpeg -threads $num_cpus -y -i -
</command>
<!-- complete encoding commands -->
<command id="normal_av_single_pass">
$ffmpeg_normal_av $ffmpeg_options $ffmpeg_single_pass_options "$output_file"
</command>
<command id="normal_av_single_pass_offset">
$ffmpeg_normal_av_offset $ffmpeg_options $ffmpeg_single_pass_options "$output_file"
</command>
<command id="normal_av_pass1">
$ffmpeg_normal_av $ffmpeg_options $ffmpeg_pass1_options "$output_file"
</command>
<command id="normal_av_pass2">
$ffmpeg_normal_av $ffmpeg_options $ffmpeg_pass2_options "$output_file"
</command>
<command id="normal_av_pass2_offset">
$ffmpeg_normal_av_offset $ffmpeg_options $ffmpeg_pass2_options "$output_file"
</command>
<command id="normal_v_single_pass">
$ffmpeg_normal_v $ffmpeg_options $ffmpeg_single_pass_options "$output_file"
</command>
<command id="normal_v_pass1">
$ffmpeg_normal_v $ffmpeg_options $ffmpeg_pass1_options "$output_file"
</command>
<command id="normal_v_pass2">
$ffmpeg_normal_v $ffmpeg_options $ffmpeg_pass2_options "$output_file"
</command>
<script>
<![CDATA[
// The first generation Apple TV could not handle 30fps 720p content. If
// you wanted 30fps you were limited to 960x540, and if you wanted
// 1024x768 you were limited to 24fps. This variable captures that
// information. Here we set it to the empty string. If it is changed
// to true or false it indicates a first generation Apple TV encode.
params.apple_tv_format_limit = "";
/*
* Utility functions
*/
function caseInsensitiveCompare(a,b) { return a.toLowerCase() == b.toLowerCase() }
function bool(v)
{
if (typeof(v) == "number")
return v != 0;
if (typeof(v) == "boolean")
return v;
if (typeof(v) == "string")
return v != "false" && v != "";
return false;
}
function number(v)
{
if (typeof(v) == "number")
return v;
if (typeof(v) == "boolean")
return v ? 1 : 0;
if (typeof(v) == "string") {
var n = parseFloat(v);
return isNaN(n) ? 0 : n;
}
return 0;
}
function string(v)
{
return v.toString();
}
function standardizeVideoCodecName(name)
{
if (caseInsensitiveCompare(name, "vc-1"))
return "wmv3";
if (caseInsensitiveCompare(name, "avc") || caseInsensitiveCompare(name, "avc1"))
return "h.264";
return name;
}
/*
* Prosessing responses
*/
function addProcessResponseCallback(f)
{
if (!("processResponseCallbacks" in params))
params.processResponseCallbacks = [ ];
params.processResponseCallbacks.push(f);
}
function processResponse(command, response)
{
// Init response values
params.processResponseProgress = -1;
params.processResponseMessage = "";
for (var i in params.processResponseCallbacks) {
if (params.processResponseCallbacks[i](command, response))
return;
}
// Response not handled, just output it
params.processResponseMessage = response;
}
addProcessResponseCallback(function(command, response)
{
// Handle all common responses
if (command == "ffmpeg") {
if (response.match(/^frame=/)) {
// This looks like a progress line for ffmpeg
var frame = number(response.replace(/^frame=/, ""));
var totalFrames = params.duration * params.output_video_frame_rate;
params.processResponseProgress = frame / totalFrames;
return true;
}
}
else if (command == "AtomicParsley") {
if (response.match(/^ Progress:/)) {
// This looks like a progress line for AtomicParsley
var array = response.split(">");
params.processResponseProgress = number(array[1]) / 100;
return true;
}
}
return false;
});
/*
* Generate params.ffmpeg_options
*/
function addFFMPegParam(param, paramName)
{
if (paramName == undefined)
paramName = "ffmpeg_option_" + param;
if (paramName in params && params[paramName] != "")
params.ffmpeg_options += "-" + param + " " + params[paramName] + " ";
}
function setFFMPegOptions()
{
var audio_codec_name = params.output_audio_codec_name_override;
if (audio_codec_name == "")
audio_codec_name = params.output_audio_codec_name;
var audio_channels = params.output_audio_channels_override;
if (audio_channels == "")
audio_channels = params.output_audio_channels;
var audio_sample_rate = params.output_audio_sample_rate_override;
if (audio_sample_rate == "")
audio_sample_rate = params.output_audio_sample_rate;
else if (params.output_audio_bitrate_override == "") {
// Make sure audio sample rate is sufficient, unless overridden
if (audio_sample_rate >= 44100 && params.output_audio_bitrate < 128000)
params.output_audio_bitrate = 128000;
else if (audio_sample_rate >= 22050 && params.output_audio_bitrate < 32000)
params.output_audio_bitrate = 32000;
else if (params.output_audio_bitrate < 16000)
params.output_audio_bitrate = 16000;
}
var audio_bitrate = params.output_audio_bitrate_override;
if (audio_bitrate == "")
audio_bitrate = params.output_audio_bitrate;
var video_codec_name = params.output_video_codec_name_override;
if (video_codec_name == "")
video_codec_name = params.output_video_codec_name;
var video_profile_name = params.output_video_profile_name_override;
if (video_profile_name == "")
video_profile_name = params.output_video_profile_name;
var video_frame_rate = params.output_video_frame_rate_override;
if (video_frame_rate == "")
video_frame_rate = params.output_video_frame_rate;
var video_width = params.output_video_width_override;
if (video_width == "")
video_width = params.output_video_width;
var video_height = params.output_video_height_override;
if (video_height == "")
video_height = params.output_video_height;
if ( params.output_video_padleft_override != "" ||
params.output_video_padright_override != "" ||
params.output_video_padtop_override != "" ||
params.output_video_padbottom_override != "") {
params.ffmpeg_option_padleft = params.output_video_padleft_override;
params.ffmpeg_option_padright = params.output_video_padright_override;
params.ffmpeg_option_padtop = params.output_video_padtop_override;
params.ffmpeg_option_padbottom = params.output_video_padbottom_override;
}
// set vpre if needed
if (video_codec_name == "H.264") {
params.ffmpeg_vpre_pass1 = "-vpre ffpresets/$ffmpeg_x264_pass1_preset ";
params.ffmpeg_vpre = "-vpre ffpresets/$ffmpeg_x264_preset ";
params.ffmpeg_vpre_profile = "-vpre ffpresets/libx264-" + video_profile_name + " ";
}
params.ffmpeg_options = "";
addFFMPegParam("target")
params.ffmpeg_options += "-s " + video_width + "x" + video_height + " ";
// If the width, height or aspect ratio are overridden, we need to adjust aspect
var video_aspect_x = params.ffmpeg_video_aspect_x;
var video_aspect_y = params.ffmpeg_video_aspect_y;
if (video_aspect_x == 0 || video_aspect_y == 0 ||
params.output_video_width_override != "" || params.output_video_height_override != "") {
video_aspect_x = video_width;
video_aspect_y = video_height;
}
var video_aspect_ratio = params.output_video_aspect_ratio_override;
if (video_aspect_ratio != "") {
video_aspect_ratio = number(video_aspect_ratio);
video_aspect_x = video_aspect_y * video_aspect_ratio;
}
params.output_video_aspect_ratio = video_aspect_x / video_aspect_y;
params.ffmpeg_options += "-aspect " + Math.round(video_aspect_x) + ":" + Math.round(video_aspect_y) + " ";
params.ffmpeg_options += "-r " + video_frame_rate + " ";
// Add padding and crop
params.ffmpeg_option_padleft = number(params.ffmpeg_option_padleft);
params.ffmpeg_option_padright = number(params.ffmpeg_option_padright);
params.ffmpeg_option_padtop = number(params.ffmpeg_option_padtop);
params.ffmpeg_option_padbottom = number(params.ffmpeg_option_padbottom);
var padleft = params.ffmpeg_option_padleft;
var padright = params.ffmpeg_option_padright;
var padtop = params.ffmpeg_option_padtop;
var padbottom = params.ffmpeg_option_padbottom;
var padwidth = video_width;
var padheight = video_height;
var padstring = "";
var cropstring = "";
if (padleft > 0 || padright > 0 || padtop > 0 || padbottom > 0) {
var padx = (padleft > 0) ? padleft : 0;
var pady = (padtop > 0) ? padtop : 0;
padwidth += padx + ((padright > 0) ? padright : 0);
padheight += pady + ((padbottom > 0) ? padbottom : 0);
padstring = "pad=" + padwidth + ":" + padheight + ":" + padx + ":" + pady;
}
if (padleft < 0 || padright < 0 || padtop < 0 || padbottom < 0) {
var cropx = (padleft < 0) ? -padleft : 0;
var cropy = (padtop < 0) ? -padtop : 0;
padwidth += -cropx + ((padright < 0) ? padright : 0);
padheight += -cropy + ((padbottom < 0) ? padbottom : 0);
cropstring = "crop=" + padwidth + ":" + padheight + ":" + cropx + ":" + cropy;
}
if (padstring != "")
if (cropstring == "")
params.ffmpeg_options += "-vf " + padstring + " ";
else
params.ffmpeg_options += "-vf " + padstring + "," + cropstring + " ";
else if (cropstring != "")
params.ffmpeg_options += "-vf " + cropstring + " ";
// padding needs to go back to app as strings
params.ffmpeg_option_padleft = string(params.ffmpeg_option_padleft);
params.ffmpeg_option_padright = string(params.ffmpeg_option_padright);
params.ffmpeg_option_padtop = string(params.ffmpeg_option_padtop);
params.ffmpeg_option_padbottom = string(params.ffmpeg_option_padbottom);
// Set ffmpeg_option_vcodec from output_video_codec_name
switch(video_codec_name) {
case "H.264": params.ffmpeg_option_vcodec = "libx264"; break;
case "MPEG-4": params.ffmpeg_option_vcodec = "mpeg4"; break;
case "WMV": params.ffmpeg_option_vcodec = "wmv1"; break;
case "FLV": params.ffmpeg_option_vcodec = "flv"; break;
case "MPEG-1": params.ffmpeg_option_vcodec = "mpeg1video"; break;
case "MPEG-2": params.ffmpeg_option_vcodec = "mpeg2video"; break;
case "Digital Video": params.ffmpeg_option_vcodec = "dvvideo"; break;
default: params.ffmpeg_option_vcodec = "libx264"; break;
}
addFFMPegParam("vcodec");
if (params.output_video_bitrate > 0)
params.ffmpeg_options += "-b:v $(output_video_bitrate) ";
addFFMPegParam("pix_fmt");
addFFMPegParam("vtag");
addFFMPegParam("g");
addFFMPegParam("maxrate");
addFFMPegParam("qmin");
addFFMPegParam("bf");
params.ffmpeg_options += "-async 50 ";
// Set ffmpeg_option_acodec from output_audio_codec_name
switch(audio_codec_name) {
case "MP3": params.ffmpeg_option_acodec = "libmp3lame"; break;
case "AAC": params.ffmpeg_option_acodec = "libvo_aacenc"; break;
case "WMA": params.ffmpeg_option_acodec = "wmav2"; break;
case "AC3": params.ffmpeg_option_acodec = "ac3"; break;
case "MP2": params.ffmpeg_option_acodec = "mp2"; break;
case "PCM": params.ffmpeg_option_acodec = "pcm_s16le"; break;
default: params.ffmpeg_option_acodec = "libmp3lame"; break;
}
addFFMPegParam("acodec");
if (audio_sample_rate > 0)
params.ffmpeg_options += "-ar " + audio_sample_rate + " ";
params.ffmpeg_options += "-ac " + audio_channels + " -ab " + audio_bitrate + " ";
addFFMPegParam("f"); // '-f vob' for MPEG-2 encode to program stream
if (params.ffmpeg_extra_options != undefined)
params.ffmpeg_options += params.ffmpeg_extra_options + " ";
}
/*
* Setting output params
*/
// Sets output_audio_bitrate, output_audio_sample_rate, output_audio_channels, output_audio_quality
function setAudioParams(type)
{
switch(type) {
case "low":
params.output_audio_bitrate = 16000;
params.output_audio_sample_rate = 16000;
params.output_audio_channels = 1;
params.output_audio_quality = "Low";
break;
case "medium":
params.output_audio_bitrate = 32000;
params.output_audio_sample_rate = 22050;
params.output_audio_channels = 1;
params.output_audio_quality = "Medium";
break;
case "cd":
params.output_audio_bitrate = 128000;
params.output_audio_sample_rate = 44100;
params.output_audio_channels = 2;
params.output_audio_quality = "CD";
break;
case "high":
params.output_audio_bitrate = 128000;
params.output_audio_sample_rate = 48000;
params.output_audio_channels = 2;
params.output_audio_quality = "High";
break;
case "hd":
params.output_audio_bitrate = 192000;
params.output_audio_sample_rate = 48000;
params.output_audio_channels = 2;
params.output_audio_quality = "High";
break;
case "default":
setAudioParams((params.quality_stop == 0) ? "low" : (params.quality_stop == 1) ? "medium" : "high");
break;
}
}
// Sets output_video_frame_rate
//
// if allowDegradedRate is true, degrade the frame rate to half rate if quality is low
function setVideoFrameRate(allowDegradedRate)
{
// set the frame rate
var rateMultiplier = 1;
if (allowDegradedRate && number(params.quality_stop) == 0 && number(params.quality) < 0.5)
rateMultiplier = 0.5;
params.output_video_frame_rate = params.input_frame_rate * rateMultiplier;
}
// Sets output_video_bitrate
function setVideoBitrate(bitrateMin, bitrateMax)
{
var bitrate = (bitrateMax - bitrateMin) * number(params.quality) + bitrateMin;
var limit = (bitrate > params.input_video_bitrate) && bool(params.limit_output_params);
params.output_video_bitrate = Math.round(limit ? params.input_video_bitrate : bitrate);
}
// Assumes output_video_frame_rate is set
// Sets output_video_width, output_video_height
function setVideoSize(requestedWidth, requestedHeight)
{
if (requestedWidth == 0)
requestedWidth = params.input_video_width;
if (requestedHeight == 0)
requestedHeight = requestedWidth * params.input_video_height / params.input_video_width;
// Set output frame size
var inputWidth = params.input_video_width;
var inputHeight = params.input_video_height;
var inputAspect = inputWidth / inputHeight;
if (Math.abs(inputAspect - params.input_video_aspect) > 0.01) {
if (inputAspect < params.input_video_aspect) {
// stretch horizontally
inputWidth = inputHeight * params.input_video_aspect;
}
else {
// stretch vertically
inputHeight = inputWidth / params.input_video_aspect;
}
}
// adjust for limit_output_params
if (bool(params.limit_output_params)) {
if (requestedWidth > inputWidth || requestedHeight > inputHeight) {
requestedWidth = inputWidth;
requestedHeight = inputHeight;
}
}
// Adjust frame rate and frame size based on format_limits for devices that
// are limited to 960x540 for framerates over 24fps (first gen Apple TV)
if (params.apple_tv_format_limit == "24fps") {
if (requestedWidth > 960 || requestedHeight > 540) {
if (params.output_video_frame_rate > 24)
params.output_video_frame_rate = 24;
if (requestedWidth > 1280)
requestedWidth = 1280;
if (requestedHeight > 1024)
requestedHeight = 1024;
}
}
else if (params.apple_tv_format_limit == "30fps"){
if (params.output_video_frame_rate > 30)
params.output_video_frame_rate = 30;
if (requestedWidth > 960)
requestedWidth = 960;
if (requestedHeight > 540)
requestedHeight = 540;
}
// adjust video frame size
inputAspect = inputWidth / inputHeight;
var requestedAspect = requestedWidth / requestedHeight;
if (inputAspect > requestedAspect) {
// shorten height
requestedHeight = requestedWidth / inputAspect;
}
else {
// shorten width
requestedWidth = requestedHeight * inputAspect;
}
// Make frame size divisible by 16
if (!bool(params.no_framesize_snap)) {
requestedWidth = Math.round(requestedWidth / 16) * 16;
requestedHeight = Math.round(requestedHeight / 16) * 16;
}
// One more problem. If we are frame size limited then
// rounding could have pushed us over that limit.
// We need to make sure the width and height
// are below the maximums.
if (params.apple_tv_format_limit == "24fps") {
if (requestedWidth > 1280)
requestedWidth -= 16;
if (requestedHeight > 1024)
requestedHeight -= 16;
}
else if (params.apple_tv_format_limit == "30fps") {
if (requestedWidth > 960)
requestedWidth -= 16;
if (requestedHeight > 540)
requestedHeight -= 16;
}
params.output_video_width = requestedWidth;
params.output_video_height = requestedHeight;
}
// Create params.recipe
function setRecipe()
{
// Set options here so recipe can pick them up
setFFMPegOptions();
var recipeType =
(bool(params.has_audio) ? 2 : 0) |
(bool(params.is_2_pass) ? 1 : 0);
var offset = (number(params.audio_offset) != 0 || number(params.video_offset) != 0) ? "_offset" : "";
switch (recipeType) {
case 0: params.recipe = "$normal_v_single_pass"; break;
case 1: params.recipe = "$normal_v_pass1 ; $normal_v_pass2"; break
case 2: params.recipe = "$normal_av_single_pass" + offset; break;
case 3: params.recipe = "$normal_av_pass1 ; $normal_av_pass2" + offset; break;
}
}
]]>
</script>
<quality>
<quality_stop title="Tiny" />
<quality_stop title="Low" />
<quality_stop title="Standard" />
<quality_stop title="High" />
<quality_stop title="Go Nuts" />
</quality>
<performance>
<performance_item title="Fastest">
<param id="is_2_pass" value="false" />
<param id="ffmpeg_x264_preset" value="libx264-ultrafast" />
</performance_item>
<performance_item title="Fast">
<param id="is_2_pass" value="false" />
<param id="ffmpeg_x264_preset" value="libx264-fast" />
</performance_item>
<performance_item title="Normal">
<param id="is_2_pass" value="false" />
<param id="ffmpeg_x264_preset" value="libx264-medium" />
</performance_item>
<performance_item title="Best (2 pass)">
<param id="is_2_pass" value="true" />
<param id="ffmpeg_x264_preset" value="libx264-slow" />
<param id="ffmpeg_x264_pass1_preset" value="libx264-slow_firstpass" />
</performance_item>
</performance>
<param id="output_video_codec_name" value="H.264" />
<param id="output_audio_codec_name" value="AAC" />
<param id="video_suffix" value="mp4" />
<param id="ffmpeg_option_pix_fmt" value="yuv420p" />
</default_device>
<devices>
<!--
iTunes Group
-->
<device_group title="iTunes">
<common_device>
<script>
<![CDATA[
// iTunes Formats -
//
// At this point, we know what 2 quality stops we are between (params.quality_stop
// and params.quality_stop+1) and we know what percentage of the way between the
// two we are (params.quality). We also know which device we have selected
// (params.title), whether we are doing h.264 or mpeg4 (params.h264), and whether
// we want to optimize for TV or iPod (params.for_tv). From this we need to
// compute requestedFrameWidth, requestedFrameHeight,
// params.output_audio_quality and params.output_video_bitrate.
// We support a number of standard frame sizes. After adjusting these sizes according to the flags
// (h264, forTV), we determine the actual frame size using these as maximum values, taking
// into account aspect ratio.
params.output_format_name = "MPEG-4";
params.output_video_codec_name = bool(params.h264) ? "H.264" : "MPEG-4"
params.output_audio_codec_name = "AAC";
var frameSizes = {
"tiny": [ 192, 144 ],
"small": [ 320, 240 ],
"iphone":[ 480, 320 ],
"sdef": [ 640, 480 ],
"idef": [ 1280, 720 ],
"hdef": [ 1920, 1080 ]
};
var deviceFrameSizeMap = {
// 0 1 2 3 4
"All Apple Devices":
[
[ "small", "iphone", "sdef", "sdef", "sdef" ], // mp4 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ], // mp4 && for TV
[ "small", "iphone", "sdef", "sdef", "sdef" ], // h.264 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ] // h.264 && for TV
],
"iPod":
[
[ "tiny", "small", "small", "small", "small" ], // mp4 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ], // mp4 && for TV
[ "tiny", "small", "small", "small", "small" ], // h.264 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ] // h.264 && for TV
],
"iPhone":
[
[ "tiny", "small", "iphone", "iphone", "iphone" ], // mp4 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ], // mp4 && for TV
[ "tiny", "small", "iphone", "iphone", "iphone" ], // h.264 && for iPod
[ "small", "iphone", "sdef", "sdef", "sdef" ] // h.264 && for TV
],