[TASK] Introduce Enum constants for t3ver_state
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / FlowPlayerContentObject.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2011-2013 Stanislas Rolland <>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Contains FlowPlayer class object.
31 *
32 * @author Stanislas Rolland
33 */
34 class FlowPlayerContentObject extends \TYPO3\CMS\Frontend\ContentObject\AbstractContentObject {
35
36 /**
37 * File extension to mime type
38 */
39 public $mimeTypes = array(
40 'aif' => array(
41 'audio' => 'audio/aiff'
42 ),
43 'au' => array(
44 'audio' => 'audio/x-au'
45 ),
46 'avi' => array(
47 'audio' => 'video/x-msvideo'
48 ),
49 'asf' => array(
50 'video' => 'video/x-ms-asf'
51 ),
52 'class' => array(
53 'audio' => 'application/java',
54 'video' => 'application/java'
55 ),
56 'dcr' => array(
57 'video' => 'application/x-director'
58 ),
59 'flac' => array(
60 'audio' => 'audio/flac'
61 ),
62 'flv' => array(
63 'video' => 'video/x-flv'
64 ),
65 'mp3' => array(
66 'audio' => 'audio/mpeg'
67 ),
68 'mp4' => array(
69 'video' => 'video/mp4'
70 ),
71 'oga' => array(
72 'audio' => 'audio/ogg'
73 ),
74 'ogg' => array(
75 'audio' => 'audio/ogg',
76 'video' => 'video/ogg'
77 ),
78 'ogv' => array(
79 'video' => 'video/ogg'
80 ),
81 'swa' => array(
82 'audio' => 'audio/x-m4a'
83 ),
84 'mov' => array(
85 'video' => 'video/quicktime'
86 ),
87 'm4a' => array(
88 'audio' => 'audio/mp4a-latm'
89 ),
90 'm4v' => array(
91 'video' => 'video/x-m4v'
92 ),
93 'qt' => array(
94 'video' => 'video/quicktime'
95 ),
96 'swa' => array(
97 'audio' => 'application/x-director'
98 ),
99 'swf' => array(
100 'audio' => 'application/x-shockwave-flash',
101 'video' => 'application/x-shockwave-flash'
102 ),
103 'wav' => array(
104 'audio' => 'audio/wave'
105 ),
106 'webm' => array(
107 'audio' => 'audio/webm',
108 'video' => 'video/webm'
109 ),
110 'wmv' => array(
111 'audio' => 'audio/x-ms-wmv'
112 )
113 );
114
115 /**
116 * VideoJS options
117 */
118 public $videoJsOptions = array(
119 // Use the browser's controls (iPhone)
120 'useBuiltInControls',
121 // Display control bar below video vs. in front of
122 'controlsBelow',
123 // Make controls visible when page loads
124 'controlsAtStart',
125 // Hide controls when not over the video
126 'controlsHiding',
127 // Will be overridden by localStorage volume if available
128 'defaultVolume',
129 // Players and order to use them
130 'playerFallbackOrder'
131 );
132
133 /**
134 * htlm5 tag attributes
135 */
136 public $html5TagAttributes = array(
137 'autoPlay',
138 'controls',
139 'loop',
140 'preload'
141 );
142
143 /**
144 * Flowplayer captions plugin configuration
145 */
146 public $flowplayerCaptionsConfig = array(
147 'plugins' => array(
148 // The captions plugin
149 'captions' => array(
150 'url' => 'plugins/flowplayer.captions-3.2.9.swf',
151 // Pointer to a content plugin (see below)
152 'captionTarget' => 'content'
153 ),
154 // Configure a content plugin so that it looks good for showing captions
155 'content' => array(
156 'url' => 'plugins/flowplayer.content-3.2.8.swf',
157 'bottom' => 5,
158 'height' => 40,
159 'backgroundColor' => 'transparent',
160 'backgroundGradient' => 'none',
161 'border' => 0,
162 'textDecoration' => 'outline',
163 'style' => array(
164 'body' => array(
165 'fontSize' => 14,
166 'fontFamily' => 'Arial',
167 'textAlign' => 'center',
168 'color' => '#ffffff'
169 )
170 )
171 )
172 )
173 );
174
175 /**
176 * Flowplayer audio configuration
177 */
178 public $flowplayerAudioConfig = array(
179 'provider' => 'audio',
180 'plugins' => array(
181 'audio' => array(
182 'url' => 'plugins/flowplayer.audio-3.2.10.swf'
183 ),
184 'controls' => array(
185 'autoHide' => FALSE,
186 'fullscreen' => FALSE
187 )
188 )
189 );
190
191 /**
192 * Flowplayer configuration for the audio description
193 */
194 public $flowplayerAudioDescriptionConfig = array(
195 // The controls plugin
196 'plugins' => array(
197 'controls' => NULL
198 )
199 );
200
201 /**
202 * Rendering the cObject, SWFOBJECT
203 *
204 * @param array $conf Array of TypoScript properties
205 * @return string Output
206 */
207 public function render($conf = array()) {
208 $prefix = '';
209 if ($GLOBALS['TSFE']->baseUrl) {
210 $prefix = $GLOBALS['TSFE']->baseUrl;
211 }
212 if ($GLOBALS['TSFE']->absRefPrefix) {
213 $prefix = $GLOBALS['TSFE']->absRefPrefix;
214 }
215 // Initialize content
216 $replaceElementIdString = uniqid('mmswf');
217 $GLOBALS['TSFE']->register['MMSWFID'] = $replaceElementIdString;
218 $layout = isset($conf['layout.']) ? $this->cObj->stdWrap($conf['layout'], $conf['layout.']) : $conf['layout'];
219 $content = str_replace('###ID###', $replaceElementIdString, $layout);
220 $type = isset($conf['type.']) ? $this->cObj->stdWrap($conf['type'], $conf['type.']) : $conf['type'];
221 $typeConf = $conf[$type . '.'];
222 // Add Flowplayer js-file
223 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/flowplayer/flowplayer-3.2.12.min.js');
224 // Add Flowpayer css for exprss install
225 $GLOBALS['TSFE']->getPageRenderer()->addCssFile(TYPO3_mainDir . 'contrib/flowplayer/express-install/express-install.css');
226 // Add videoJS js-file
227 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/videojs/video-js/video.js');
228 // Add videoJS js-file
229 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/videojs/video-js/video.js');
230 // Add videoJS css-file
231 $GLOBALS['TSFE']->getPageRenderer()->addCssFile(TYPO3_mainDir . 'contrib/videojs/video-js/video-js.css');
232 // Add extended videoJS control bar
233 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/videojs/video-js/controls/control-bar.js');
234 $GLOBALS['TSFE']->getPageRenderer()->addCssFile(TYPO3_mainDir . 'contrib/videojs/video-js/controls/control-bar.css');
235 // Build Flash configuration
236 $player = isset($typeConf['player.']) ? $this->cObj->stdWrap($typeConf['player'], $typeConf['player.']) : $typeConf['player'];
237 if (!$player) {
238 $player = $prefix . TYPO3_mainDir . 'contrib/flowplayer/flowplayer-3.2.16.swf';
239 }
240 $installUrl = isset($conf['installUrl.']) ? $this->cObj->stdWrap($conf['installUrl'], $conf['installUrl.']) : $conf['installUrl'];
241 if (!$installUrl) {
242 $installUrl = $prefix . TYPO3_mainDir . 'contrib/flowplayer/expressinstall.swf';
243 }
244 $flashVersion = isset($conf['flashVersion.']) ? $this->cObj->stdWrap($conf['flashVersion'], $conf['flashVersion.']) : $conf['flashVersion'];
245 if (!$flashVersion) {
246 $flashVersion = array(9, 115);
247 }
248 $flashConfiguration = array(
249 // Flowplayer component
250 'src' => $player,
251 // Express install url
252 'expressInstall' => $installUrl,
253 // Require at least this Flash version
254 'version' => $flashVersion,
255 // Older versions will see a message
256 'onFail' => '###ONFAIL###'
257 );
258 $flashDownloadUrl = 'http://www.adobe.com/go/getflashplayer';
259 $onFail = 'function() {
260 if (!(flashembed.getVersion()[0] > 0)) {
261 var message = "<p>" + "' . $GLOBALS['TSFE']->sL('LLL:EXT:cms/locallang_ttc.xlf:media.needFlashPlugin') . '" + "</p>" + "<p>" + "<a href=\\"' . $flashDownloadUrl . '\\">' . $GLOBALS['TSFE']->sL('LLL:EXT:cms/locallang_ttc.xlf:media.downloadFlash') . '</a>" + "</p>";
262 document.getElementById("' . $replaceElementIdString . '_flash_install_info").innerHTML = "<div class=\\"message\\">" + message + "</div>";
263 }
264 }';
265 $flashConfiguration = json_encode($flashConfiguration);
266 $flashConfiguration = str_replace('"###ONFAIL###"', $onFail, $flashConfiguration);
267 $filename = isset($conf['file.']) ? $this->cObj->stdWrap($conf['file'], $conf['file.']) : $conf['file'];
268 if ($filename) {
269 if (strpos($filename, '://') !== FALSE) {
270 $conf['flashvars.']['url'] = $filename;
271 } else {
272 if ($prefix) {
273 $conf['flashvars.']['url'] = $prefix . $filename;
274 } else {
275 $conf['flashvars.']['url'] = str_repeat('../', substr_count($player, '/')) . $filename;
276 }
277 }
278 }
279 if (is_array($conf['sources'])) {
280 foreach ($conf['sources'] as $key => $source) {
281 if (strpos($source, '://') === FALSE) {
282 $conf['sources'][$key] = $prefix . $source;
283 }
284 }
285 }
286 if (is_array($conf['audioSources'])) {
287 foreach ($conf['audioSources'] as $key => $source) {
288 if (strpos($source, '://') === FALSE) {
289 $conf['audioSources'][$key] = $prefix . $source;
290 }
291 }
292 }
293 if (isset($conf['audioFallback']) && strpos($conf['audioFallback'], '://') === FALSE) {
294 $conf['audioFallback'] = $prefix . $conf['audioFallback'];
295 }
296 if (isset($conf['caption']) && strpos($conf['caption'], '://') === FALSE) {
297 $conf['caption'] = $prefix . $conf['caption'];
298 }
299 // Write calculated values in conf for the hook
300 $conf['player'] = $player ? $player : $filename;
301 $conf['installUrl'] = $installUrl;
302 $conf['filename'] = $conf['flashvars.']['url'];
303 $conf['prefix'] = $prefix;
304 // merge with default parameters
305 $conf['flashvars.'] = array_merge((array) $typeConf['default.']['flashvars.'], (array) $conf['flashvars.']);
306 $conf['params.'] = array_merge((array) $typeConf['default.']['params.'], (array) $conf['params.']);
307 $conf['attributes.'] = array_merge((array) $typeConf['default.']['attributes.'], (array) $conf['attributes.']);
308 $conf['embedParams'] = 'flashvars, params, attributes';
309 // Hook for manipulating the conf array, it's needed for some players like flowplayer
310 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'])) {
311 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/hooks/class.tx_cms_mediaitems.php']['swfParamTransform'] as $classRef) {
312 \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($classRef, $conf, $this);
313 }
314 }
315 // Flowplayer config
316 $flowplayerVideoConfig = array();
317 $flowplayerAudioConfig = array();
318 if (is_array($conf['flashvars.'])) {
319 \TYPO3\CMS\Core\Utility\GeneralUtility::remapArrayKeys($conf['flashvars.'], $typeConf['mapping.']['flashvars.']);
320 } else {
321 $conf['flashvars.'] = array();
322 }
323 $conf['videoflashvars'] = $conf['flashvars.'];
324 $conf['audioflashvars'] = $conf['flashvars.'];
325 $conf['audioflashvars']['url'] = $conf['audioFallback'];
326 // Render video sources
327 $videoSources = '';
328 if (is_array($conf['sources'])) {
329 foreach ($conf['sources'] as $source) {
330 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
331 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video'];
332 $videoSources .= '<source src="' . $source . '"' . ($mimeType ? ' type="' . $mimeType . '"' : '') . ' />' . LF;
333 }
334 }
335 // Render audio sources
336 $audioSources = '';
337 if (is_array($conf['audioSources'])) {
338 foreach ($conf['audioSources'] as $source) {
339 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
340 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio'];
341 $audioSources .= '<source src="' . $source . '"' . ($mimeType ? ' type="' . $mimeType . '"' : '') . ' />' . LF;
342 }
343 }
344 // Configure captions
345 if ($conf['type'] === 'video' && isset($conf['caption'])) {
346 // Assemble captions track tag
347 $videoCaptions = '<track id="' . $replaceElementIdString . '_captions_track" kind="captions" src="' . $conf['caption'] . '"></track>' . LF;
348 // Add videoJS extension for captions
349 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/videojs/video-js/controls/captions.js');
350 // Flowplayer captions
351 $conf['videoflashvars']['captionUrl'] = $conf['caption'];
352 // Flowplayer captions plugin configuration
353 $flowplayerVideoConfig = array_merge_recursive($flowplayerVideoConfig, $this->flowplayerCaptionsConfig);
354 }
355 // Configure flowplayer audio fallback
356 if (isset($conf['audioFallback'])) {
357 $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, $this->flowplayerAudioConfig);
358 }
359 // Configure audio description
360 if ($conf['type'] == 'video') {
361 if (is_array($conf['audioSources']) && count($conf['audioSources'])) {
362 // Add videoJS audio description toggle
363 $GLOBALS['TSFE']->getPageRenderer()->addJsFile(TYPO3_mainDir . 'contrib/videojs/video-js/controls/audio-description.js');
364 }
365 if (isset($conf['audioFallback'])) {
366 // Audio description flowplayer config (remove controls)
367 $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, $this->flowplayerAudioDescriptionConfig);
368 }
369 }
370 // Assemble Flowplayer configuration
371 if (count($conf['videoflashvars'])) {
372 $flowplayerVideoConfig = array_merge_recursive($flowplayerVideoConfig, array('clip' => $conf['videoflashvars']));
373 }
374 $flowplayerVideoJsonConfig = str_replace(array('"true"', '"false"'), array('true', 'false'), json_encode($flowplayerVideoConfig));
375 if (count($conf['audioflashvars'])) {
376 $flowplayerAudioConfig = array_merge_recursive($flowplayerAudioConfig, array('clip' => $conf['audioflashvars']));
377 }
378 $flowplayerAudioJsonConfig = str_replace(array('"true"', '"false"'), array('true', 'false'), json_encode($flowplayerAudioConfig));
379 // Assemble param tags (required?)
380 if (is_array($conf['params.'])) {
381 \TYPO3\CMS\Core\Utility\GeneralUtility::remapArrayKeys($conf['params.'], $typeConf['mapping.']['params.']);
382 }
383 $videoFlashParams = '';
384 if (is_array($conf['params.'])) {
385 foreach ($conf['params.'] as $name => $value) {
386 $videoFlashParams .= '<param name="' . $name . '" value="' . $value . '" />' . LF;
387 }
388 }
389 $audioFlashParams = $videoFlashParams;
390 // Required param tags
391 $videoFlashParams .= '<param name="movie" value="' . $player . '" />' . LF;
392 $videoFlashParams .= '<param name="flashvars" value=\'config=' . $flowplayerVideoJsonConfig . '\' />' . LF;
393 $audioFlashParams .= '<param name="movie" value="' . $player . '" />' . LF;
394 $audioFlashParams .= '<param name="flashvars" value=\'config=' . $flowplayerAudioJsonConfig . '\' />' . LF;
395 // Assemble audio/video tag attributes
396 $attributes = '';
397 if (is_array($conf['attributes.'])) {
398 \TYPO3\CMS\Core\Utility\GeneralUtility::remapArrayKeys($conf['attributes.'], $typeConf['attributes.']['params.']);
399 }
400 foreach ($this->html5TagAttributes as $attribute) {
401 if ($conf['attributes.'][$attribute] === 'true' || $conf['attributes.'][$attribute] === strToLower($attribute) || $conf['attributes.'][$attribute] === $attribute) {
402 $attributes .= strToLower($attribute) . '="' . strToLower($attribute) . '" ';
403 }
404 }
405 // Media dimensions
406 $width = isset($conf['width.']) ? $this->cObj->stdWrap($conf['width'], $conf['width.']) : $conf['width'];
407 if (!$width) {
408 $width = $conf[$type . '.']['defaultWidth'];
409 }
410 $height = isset($conf['height.']) ? $this->cObj->stdWrap($conf['height'], $conf['height.']) : $conf['height'];
411 if (!$height) {
412 $height = $conf[$type . '.']['defaultHeight'];
413 }
414 // Alternate content
415 $alternativeContent = isset($conf['alternativeContent.']) ? $this->cObj->stdWrap($conf['alternativeContent'], $conf['alternativeContent.']) : $conf['alternativeContent'];
416 // Render video
417 if ($conf['type'] === 'video') {
418 if ($conf['preferFlashOverHtml5']) {
419 // Flash with video tag fallback
420 $conf['params.']['playerFallbackOrder'] = array('flash', 'html5');
421 $flashDivContent = $videoFlashParams . LF . '<video id="' . $replaceElementIdString . '_video_js" class="video-js" ' . $attributes . 'controls="controls" mediagroup="' . $replaceElementIdString . '" width="' . $width . '" height="' . $height . '">' . LF . $videoSources . $videoCaptions . $alternativeContent . LF . '</video>' . LF;
422 $divContent = '
423 <div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF . '<noscript>' . LF . '<object id="' . $replaceElementIdString . '_vjs_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $flashDivContent . '</object>' . LF . '</noscript>' . LF;
424 $content = str_replace('###SWFOBJECT###', '<div id="' . $replaceElementIdString . '_video" class="flashcontainer" style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $divContent . '</div>', $content);
425 } else {
426 // Video tag with Flash fallback
427 $conf['params.']['playerFallbackOrder'] = array('html5', 'flash');
428 $videoTagContent = $videoSources . $videoCaptions;
429 if (isset($conf['videoflashvars']['url'])) {
430 $videoTagContent .= '
431 <noscript>' . LF . '<object class="vjs-flash-fallback" id="' . $replaceElementIdString . '_vjs_flash_fallback" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $videoFlashParams . LF . $alternativeContent . LF . '</object>' . LF . '</noscript>';
432 }
433 $divContent = '
434 <div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF . '<video id="' . $replaceElementIdString . '_video_js" class="video-js" ' . $attributes . 'controls="controls" mediagroup="' . $replaceElementIdString . '" width="' . $width . '" height="' . $height . '">' . LF . $videoTagContent . '</video>';
435 $content = str_replace('###SWFOBJECT###', '<div id="' . $replaceElementIdString . '_video" class="video-js-box" style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $divContent . '</div>', $content);
436 }
437 }
438 // Render audio
439 if ($conf['type'] === 'audio' || $audioSources || isset($conf['audioFallback'])) {
440 if ($conf['preferFlashOverHtml5']) {
441 // Flash with audio tag fallback
442 $flashDivContent = $audioFlashParams . LF . '<audio id="' . $replaceElementIdString . '_audio_element"' . $attributes . ($conf['type'] === 'video' ? ' mediagroup="' . $replaceElementIdString . 'style="position:absolute;left:-10000px;"' : ' controls="controls"') . ' style="width:' . $width . 'px; height:' . $height . 'px;">' . LF . $audioSources . $alternativeContent . LF . '</audio>' . LF;
443 $divContent = ($conf['type'] === 'video' ? '' : '<div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF) . '<noscript>' . LF . '<object id="' . $replaceElementIdString . '_audio_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . ($conf['type'] === 'video' ? 0 : $width) . '" height="' . ($conf['type'] === 'video' ? 0 : $height) . '">' . LF . $flashDivContent . '</object>' . LF . '</noscript>' . LF;
444 $audioContent = '<div id="' . $replaceElementIdString . '_audio_box" class="audio-flash-container" style="width:' . ($conf['type'] === 'video' ? 0 : $width) . 'px; height:' . ($conf['type'] === 'video' ? 0 : $height) . 'px;">' . LF . $divContent . '</div>';
445 } else {
446 // Audio tag with Flash fallback
447 $audioTagContent = $audioSources;
448 if (isset($conf['audioflashvars']['url'])) {
449 $audioTagContent .= '
450 <noscript>' . LF . '<object class="audio-flash-fallback" id="' . $replaceElementIdString . '_audio_flash" type="application/x-shockwave-flash" data="' . $player . '" width="' . $width . '" height="' . $height . '">' . LF . $audioFlashParams . LF . $alternativeContent . LF . '</object>' . LF . '</noscript>';
451 }
452 $divContent = ($conf['type'] === 'video' ? '' : '<div id="' . $replaceElementIdString . '_flash_install_info" class="flash-install-info"></div>' . LF) . '<audio id="' . $replaceElementIdString . '_audio_element" class="audio-element"' . $attributes . ($conf['type'] === 'video' ? ' mediagroup="' . $replaceElementIdString . '" style="position:absolute;left:-10000px;"' : ' controls="controls"') . '>' . LF . $audioTagContent . '</audio>' . LF . $audioSourcesEmbeddingJsScript;
453 $audioContent = '<div id="' . $replaceElementIdString . '_audio_box" class="audio-box" style="width:' . ($conf['type'] === 'video' ? 0 : $width) . 'px; height:' . ($conf['type'] === 'video' ? 0 : $height) . 'px;">' . LF . $divContent . '</div>';
454 }
455 if ($conf['type'] === 'audio') {
456 $content = str_replace('###SWFOBJECT###', $audioContent, $content);
457 } else {
458 $content .= LF . $audioContent;
459 }
460 }
461 // Assemble inline JS code
462 $videoJsSetup = '';
463 $flowplayerHandlers = '';
464 if ($conf['type'] === 'video') {
465 // Assemble videoJS options
466 $videoJsOptions = array();
467 foreach ($this->videoJsOptions as $videoJsOption) {
468 if (isset($conf['params.'][$videoJsOption])) {
469 $videoJsOptions[$videoJsOption] = $conf['params.'][$videoJsOption];
470 }
471 }
472 $videoJsOptions = count($videoJsOptions) ? json_encode($videoJsOptions) : '{}';
473 // videoJS setup and videoJS listeners for audio description synchronisation
474 if ($audioSources || isset($conf['audioFallback'])) {
475 $videoJsSetup = '
476 var ' . $replaceElementIdString . '_video = VideoJS.setup("' . $replaceElementIdString . '_video_js", ' . $videoJsOptions . ');
477 var ' . $replaceElementIdString . '_video_element = document.getElementById("' . $replaceElementIdString . '_video_js");
478 var ' . $replaceElementIdString . '_audio_element = document.getElementById("' . $replaceElementIdString . '_audio_element");
479 if (!!' . $replaceElementIdString . '_video_element && !!' . $replaceElementIdString . '_audio_element) {
480 ' . $replaceElementIdString . '_audio_element.muted = true;
481 VideoJS.addListener(' . $replaceElementIdString . '_video_element, "pause", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").pause(); });
482 VideoJS.addListener(' . $replaceElementIdString . '_video_element, "play", function () { try {document.getElementById("' . $replaceElementIdString . '_audio_element").currentTime = document.getElementById("' . $replaceElementIdString . '_video_js").currentTime} catch(e) {}; document.getElementById("' . $replaceElementIdString . '_audio_element").play(); });
483 VideoJS.addListener(' . $replaceElementIdString . '_video_element, "seeked", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").currentTime = document.getElementById("' . $replaceElementIdString . '_video_js").currentTime; });
484 VideoJS.addListener(' . $replaceElementIdString . '_video_element, "volumechange", function () { document.getElementById("' . $replaceElementIdString . '_audio_element").volume = document.getElementById("' . $replaceElementIdString . '_video_js").volume; });
485 }';
486 } else {
487 $videoJsSetup = '
488 var ' . $replaceElementIdString . '_video = VideoJS.setup("' . $replaceElementIdString . '_video_js", ' . $videoJsOptions . ');
489 ';
490 }
491 // Prefer Flash or fallback to Flash
492 $videoSourcesEmbedding = '';
493 // If we have a video file for Flash
494 if (isset($conf['filename'])) {
495 // If we prefer Flash
496 if ($conf['preferFlashOverHtml5']) {
497 $videoTagAssembly = '';
498 // Create "source" elements
499 if (is_array($conf['sources']) && count($conf['sources'])) {
500 foreach ($conf['sources'] as $source) {
501 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
502 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video'];
503 $videoTagAssembly .= '
504 ' . $replaceElementIdString . '_video_js.appendChild($f.extend(document.createElement("source"), {
505 src: "' . $source . '",
506 type: "' . $mimeType . '"
507 }));';
508 }
509 // Create "track" elements
510 if (isset($conf['caption'])) {
511 // Assemble captions track tag
512 // It will take a while before the captions are loaded and parsed...
513 $videoTagAssembly .= '
514 var track = document.createElement("track");
515 track.setAttribute("src", "' . $conf['caption'] . '");
516 track.setAttribute("id", "' . $replaceElementIdString . '_captions_track");
517 track.setAttribute("kind", "captions");
518 ' . $replaceElementIdString . '_video_js.appendChild(track);';
519 }
520 $videoTagAssembly .= '
521 $f.extend(' . $replaceElementIdString . '_video_js, {
522 id: "' . $replaceElementIdString . '_video_js",
523 className: "video-js",
524 controls: "controls",
525 mediagroup: "' . $replaceElementIdString . '",
526 preload: "none",
527 width: "' . $width . '",
528 height: "' . $height . '"
529 });
530 ' . $replaceElementIdString . '_video.appendChild(' . $replaceElementIdString . '_video_js);
531 ' . $replaceElementIdString . '_video.className = "video-js-box";';
532 $videoTagAssembly .= $videoJsSetup;
533 }
534 $videoSourcesEmbedding = '
535 var ' . $replaceElementIdString . '_video = document.getElementById("' . $replaceElementIdString . '_video");
536 var ' . $replaceElementIdString . '_video_js = document.createElement("video");
537 if (flashembed.getVersion()[0] > 0) {
538 // Flash is available
539 var videoPlayer = flowplayer("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ', ' . $flowplayerVideoJsonConfig . ').load();
540 videoPlayer.onBeforeUnload(function () { return false; });
541 } else if (!!' . $replaceElementIdString . '_video_js.canPlayType) {
542 // Flash is not available: fallback to videoJS if video tag is supported
543 ' . $videoTagAssembly . '
544 } else {
545 // Neither Flash nor video is available: offer to install Flash
546 flashembed("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ');
547 }';
548 } elseif (is_array($conf['sources'])) {
549 // HTML5 is the preferred rendering method
550 // Test whether the browser supports any of types of the provided sources
551 $supported = array();
552 foreach ($conf['sources'] as $source) {
553 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
554 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['video'];
555 $supported[] = $replaceElementIdString . '_videoTag.canPlayType("' . $mimeType . '") != ""';
556 }
557 // Testing whether the browser supports the video tag with any of the provided source types
558 // If no support, embed flowplayer
559 $videoSourcesEmbedding = '
560 var ' . $replaceElementIdString . '_videoTag = document.createElement(\'video\');
561 var ' . $replaceElementIdString . '_video_box = document.getElementById("' . $replaceElementIdString . '_video");
562 if (' . $replaceElementIdString . '_video_box) {
563 if (!' . $replaceElementIdString . '_videoTag || !' . $replaceElementIdString . '_videoTag.canPlayType || !(' . (count($supported) ? implode(' || ', $supported) : 'false') . ')) {
564 // Avoid showing an empty video element
565 if (document.getElementById("' . $replaceElementIdString . '_video_js")) {
566 document.getElementById("' . $replaceElementIdString . '_video_js").style.display = "none";
567 }
568 if (flashembed.getVersion()[0] > 0) {
569 // Flash is available
570 var videoPlayer = flowplayer("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ', ' . $flowplayerVideoJsonConfig . ').load();
571 videoPlayer.onBeforeUnload(function () { return false; });
572 } else {
573 // Neither Flash nor video is available: offer to install Flash
574 flashembed("' . $replaceElementIdString . '_video", ' . $flashConfiguration . ');
575 }
576 } else {' . $videoJsSetup . '
577 }
578 }';
579 }
580 }
581 }
582 // Audio fallback to Flash
583 $audioSourcesEmbedding = '';
584 // If we have an audio file for Flash
585 if (isset($conf['audioFallback'])) {
586 // If we prefer Flash in
587 if ($conf['preferFlashOverHtml5']) {
588 $audioTagAssembly = '';
589 // Create "source" elements
590 if (is_array($conf['audioSources']) && count($conf['audioSources'])) {
591 foreach ($conf['audioSources'] as $source) {
592 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
593 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio'];
594 $audioTagAssembly .= '
595 ' . $replaceElementIdString . '_audio_element.appendChild($f.extend(document.createElement("source"), {
596 src: "' . $source . '",
597 type: "' . $mimeType . '"
598 }));';
599 }
600 $audioTagAssembly .= '
601 $f.extend(' . $replaceElementIdString . '_audio_element, {
602 id: "' . $replaceElementIdString . '_audio_element",
603 className: "audio-element",
604 controls: "' . ($conf['type'] === 'video' ? '' : 'controls') . '",
605 mediagroup: "' . $replaceElementIdString . '",
606 preload: "none",
607 width: "' . ($conf['type'] === 'video' ? 0 : $width) . 'px",
608 height: "' . ($conf['type'] === 'video' ? 0 : $height) . 'px"
609 });
610 ' . $replaceElementIdString . '_audio_box.appendChild(' . $replaceElementIdString . '_audio_element);
611 ' . $replaceElementIdString . '_audio_box.className = "audio-box";';
612 }
613 $audioSourcesEmbedding = '
614 var ' . $replaceElementIdString . '_audio_box = document.getElementById("' . $replaceElementIdString . '_audio_box");
615 var ' . $replaceElementIdString . '_audio_element = document.createElement("audio");
616 if (flashembed.getVersion()[0] > 0) {
617 // Flash is available
618 var audioPlayer = flowplayer("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ', ' . $flowplayerAudioJsonConfig . ').load();
619 audioPlayer.onBeforeUnload(function () { return false; });
620 ' . ($conf['type'] === 'video' ? 'audioPlayer.mute();' : '') . '
621 } else if (!!' . $replaceElementIdString . '_audio_element.canPlayType) {
622 // Flash is not available: fallback to audio element if audio tag is supported
623 ' . $audioTagAssembly . '
624 } else {
625 // Neither Flash nor audio is available: offer to install Flash if this is not an audio description of a video
626 ' . ($conf['type'] === 'video' ? '' : 'flashembed("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ');') . '
627 }';
628 } elseif (is_array($conf['audioSources'])) {
629 // HTML5 is the preferred rendering method
630 // Test whether the browser supports any of types of the provided sources
631 $supported = array();
632 foreach ($conf['audioSources'] as $source) {
633 $fileinfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($source);
634 $mimeType = $this->mimeTypes[$fileinfo['fileext']]['audio'];
635 $supported[] = $replaceElementIdString . '_audioTag.canPlayType("' . $mimeType . '") != ""';
636 }
637 // Testing whether the browser supports the audio tag with any of the provided source types
638 // If no support, embed flowplayer
639 $audioSourcesEmbedding = '
640 var ' . $replaceElementIdString . '_audioTag = document.createElement(\'audio\');
641 var ' . $replaceElementIdString . '_audio_box = document.getElementById("' . $replaceElementIdString . '_audio_box");
642 if (' . $replaceElementIdString . '_audio_box) {
643 if (!' . $replaceElementIdString . '_audioTag || !' . $replaceElementIdString . '_audioTag.canPlayType || !(' . (count($supported) ? implode(' || ', $supported) : 'false') . ')) {
644 // Avoid showing an empty audio element
645 if (document.getElementById("' . $replaceElementIdString . '_audio_element")) {
646 document.getElementById("' . $replaceElementIdString . '_audio_element").style.display = "none";
647 }
648 if (flashembed.getVersion()[0] > 0) {
649 var audioPlayer = flowplayer("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ', ' . $flowplayerAudioJsonConfig . ').load();
650 audioPlayer.onBeforeUnload(function () { return false; });
651 ' . ($conf['type'] === 'video' ? 'audioPlayer.mute()' : '') . '
652 } else {
653 // Neither Flash nor audio is available: offer to install Flash if this is not an audio description of a video
654 ' . ($conf['type'] === 'video' ? '' : 'flashembed("' . $replaceElementIdString . '_audio_box", ' . $flashConfiguration . ');') . '
655 }
656 }
657 }';
658 }
659 // Flowplayer eventHandlers for audio description synchronisation
660 $flowplayerHandlers = '';
661 if ($conf['type'] === 'video') {
662 $flowplayerHandlers = '
663 if (flashembed.getVersion()[0] > 0) {
664 // Flash is available
665 var videoPlayer = flowplayer("' . $replaceElementIdString . '_video");
666 if (videoPlayer) {
667 // Control audio description through video control bar
668 videoPlayer.onVolume(function (volume) { flowplayer("' . $replaceElementIdString . '_audio_box").setVolume(volume); });
669 videoPlayer.onMute(function () { flowplayer("' . $replaceElementIdString . '_audio_box").mute(); });
670 videoPlayer.onUnmute(function () { flowplayer("' . $replaceElementIdString . '_audio_box").unmute(); });
671 videoPlayer.onPause(function () { flowplayer("' . $replaceElementIdString . '_audio_box").pause(); });
672 videoPlayer.onResume(function () { flowplayer("' . $replaceElementIdString . '_audio_box").resume(); });
673 videoPlayer.onStart(function () { flowplayer("' . $replaceElementIdString . '_audio_box").play(); });
674 videoPlayer.onStop(function () { flowplayer("' . $replaceElementIdString . '_audio_box").stop(); });
675 videoPlayer.onSeek(function (clip, seconds) { flowplayer("' . $replaceElementIdString . '_audio_box").seek(seconds); });
676 // Mute audio description on start
677 flowplayer("' . $replaceElementIdString . '_audio_box").onStart(function () { this.mute()});
678 // Audio description toggle
679 var videoContainer = document.getElementById("' . $replaceElementIdString . '_video");
680 var buttonContainer = document.createElement("div");
681 $f.extend(buttonContainer, {
682 id: "' . $replaceElementIdString . '_audio_description_toggle",
683 className: "vjs-audio-description-control"
684 });
685 var button = document.createElement("div");
686 buttonContainer.appendChild(button);
687 buttonContainer.style.position = "relative";
688 buttonContainer.style.left = (parseInt(' . $width . ', 10)-27) + "px";
689 videoContainer.parentNode.insertBefore(buttonContainer, videoContainer.nextSibling);
690 VideoJS.addListener(buttonContainer, "click", function () {
691 var buttonContainer = document.getElementById("' . $replaceElementIdString . '_audio_description_toggle");
692 var state = buttonContainer.getAttribute("data-state");
693 if (state == "enabled") {
694 buttonContainer.setAttribute("data-state", "disabled");
695 flowplayer("' . $replaceElementIdString . '_audio_box").mute();
696 } else {
697 buttonContainer.setAttribute("data-state", "enabled");
698 flowplayer("' . $replaceElementIdString . '_audio_box").unmute();
699 }
700 });
701 }
702 }';
703 }
704 }
705 // Wrap up inline JS code
706 $jsInlineCode = $audioSourcesEmbedding . $videoSourcesEmbedding . $flowplayerHandlers;
707 if ($jsInlineCode) {
708 $jsInlineCode = 'VideoJS.DOMReady(function(){' . $jsInlineCode . LF . '});';
709 }
710 $GLOBALS['TSFE']->getPageRenderer()->addJsInlineCode($replaceElementIdString, $jsInlineCode);
711 if (isset($conf['stdWrap.'])) {
712 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
713 }
714 return $content;
715 }
716
717 }