2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * Classes for handling embedded media (mainly audio and video).
20 * These are used only from within the core media renderer.
22 * To embed media from Moodle code, do something like the following:
24 * $mediarenderer = $PAGE->get_renderer('core', 'media');
25 * echo $mediarenderer->embed_url(new moodle_url('http://example.org/a.mp3'));
27 * You do not need to require this library file manually. Getting the renderer
28 * (the first line above) requires this library file automatically.
31 * @copyright 2012 The Open University
32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 defined('MOODLE_INTERNAL') ||
die();
37 if (!defined('CORE_MEDIA_VIDEO_WIDTH')) {
38 // Default video width if no width is specified; some players may do something
39 // more intelligent such as use real video width.
40 // May be defined in config.php if required.
41 define('CORE_MEDIA_VIDEO_WIDTH', 400);
43 if (!defined('CORE_MEDIA_VIDEO_HEIGHT')) {
44 // Default video height. May be defined in config.php if required.
45 define('CORE_MEDIA_VIDEO_HEIGHT', 300);
47 if (!defined('CORE_MEDIA_AUDIO_WIDTH')) {
48 // Default audio width if no width is specified.
49 // May be defined in config.php if required.
50 define('CORE_MEDIA_AUDIO_WIDTH', 300);
55 * Constants and static utility functions for use with core_media_renderer.
57 * @copyright 2011 The Open University
58 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
60 abstract class core_media
{
62 * Option: Disable text link fallback.
64 * Use this option if you are going to print a visible link anyway so it is
65 * pointless to have one as fallback.
67 * To enable, set value to true.
69 const OPTION_NO_LINK
= 'nolink';
72 * Option: When embedding, if there is no matching embed, do not use the
73 * default link fallback player; instead return blank.
75 * This is different from OPTION_NO_LINK because this option still uses the
76 * fallback link if there is some kind of embedding. Use this option if you
77 * are going to check if the return value is blank and handle it specially.
79 * To enable, set value to true.
81 const OPTION_FALLBACK_TO_BLANK
= 'embedorblank';
84 * Option: Enable players which are only suitable for use when we trust the
85 * user who embedded the content.
87 * At present, this option enables the SWF player.
89 * To enable, set value to true.
91 const OPTION_TRUSTED
= 'trusted';
94 * Option: Put a div around the output (if not blank) so that it displays
95 * as a block using the 'resourcecontent' CSS class.
97 * To enable, set value to true.
99 const OPTION_BLOCK
= 'block';
102 * Given a string containing multiple URLs separated by #, this will split
103 * it into an array of moodle_url objects suitable for using when calling
104 * embed_alternatives.
106 * Note that the input string should NOT be html-escaped (i.e. if it comes
107 * from html, call html_entity_decode first).
109 * @param string $combinedurl String of 1 or more alternatives separated by #
110 * @param int $width Output variable: width (will be set to 0 if not specified)
111 * @param int $height Output variable: height (0 if not specified)
112 * @return array Array of 1 or more moodle_url objects
114 public static function split_alternatives($combinedurl, &$width, &$height) {
115 $urls = explode('#', $combinedurl);
118 $returnurls = array();
120 foreach ($urls as $url) {
123 // You can specify the size as a separate part of the array like
124 // #d=640x480 without actually including a url in it.
125 if (preg_match('/^d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) {
126 $width = $matches[1];
127 $height = $matches[2];
131 // Can also include the ?d= as part of one of the URLs (if you use
132 // more than one they will be ignored except the last).
133 if (preg_match('/\?d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) {
134 $width = $matches[1];
135 $height = $matches[2];
138 $url = str_replace($matches[0], '', $url);
142 $url = clean_param($url, PARAM_URL
);
147 // Turn it into moodle_url object.
148 $returnurls[] = new moodle_url($url);
155 * Returns the file extension for a URL.
156 * @param moodle_url $url URL
158 public static function get_extension(moodle_url
$url) {
159 // Note: Does not use core_text (. is UTF8-safe).
160 $filename = self
::get_filename($url);
161 $dot = strrpos($filename, '.');
162 if ($dot === false) {
165 return strtolower(substr($filename, $dot +
1));
170 * Obtains the filename from the moodle_url.
171 * @param moodle_url $url URL
172 * @return string Filename only (not escaped)
174 public static function get_filename(moodle_url
$url) {
177 // Use the 'file' parameter if provided (for links created when
178 // slasharguments was off). If not present, just use URL path.
179 $path = $url->get_param('file');
181 $path = $url->get_path();
184 // Remove everything before last / if present. Does not use textlib as / is UTF8-safe.
185 $slash = strrpos($path, '/');
186 if ($slash !== false) {
187 $path = substr($path, $slash +
1);
193 * Guesses MIME type for a moodle_url based on file extension.
194 * @param moodle_url $url URL
195 * @return string MIME type
197 public static function get_mimetype(moodle_url
$url) {
198 return mimeinfo('type', self
::get_filename($url));
204 * Base class for media players.
206 * Media players return embed HTML for a particular way of playing back audio
207 * or video (or another file type).
209 * In order to make the code more lightweight, this is not a plugin type
210 * (players cannot have their own settings, database tables, capabilities, etc).
211 * These classes are used only by core_media_renderer in outputrenderers.php.
212 * If you add a new class here (in core code) you must modify the
213 * get_players_raw function in that file to include it.
215 * If a Moodle installation wishes to add extra player objects they can do so
216 * by overriding that renderer in theme, and overriding the get_players_raw
217 * function. The new player class should then of course be defined within the
218 * custom theme or other suitable location, not in this file.
220 * @copyright 2011 The Open University
221 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
223 abstract class core_media_player
{
225 * Placeholder text used to indicate where the fallback content is placed
228 const PLACEHOLDER
= '<!--FALLBACK-->';
231 * Generates code required to embed the player.
233 * The returned code contains a placeholder comment '<!--FALLBACK-->'
234 * (constant core_media_player::PLACEHOLDER) which indicates the location
235 * where fallback content should be placed in the event that this type of
236 * player is not supported by user browser.
238 * The $urls parameter includes one or more alternative media formats that
239 * are supported by this player. It does not include formats that aren't
240 * supported (see list_supported_urls).
242 * The $options array contains key-value pairs. See OPTION_xx constants
243 * for documentation of standard option(s).
245 * @param array $urls URLs of media files
246 * @param string $name Display name; '' to use default
247 * @param int $width Optional width; 0 to use default
248 * @param int $height Optional height; 0 to use default
249 * @param array $options Options array
250 * @return string HTML code for embed
252 public abstract function embed($urls, $name, $width, $height, $options);
255 * Gets the list of file extensions supported by this media player.
257 * Note: This is only required for the default implementation of
258 * list_supported_urls. If you override that function to determine
259 * supported URLs in some way other than by extension, then this function
262 * @return array Array of strings (extension not including dot e.g. 'mp3')
264 public function get_supported_extensions() {
269 * Lists keywords that must be included in a url that can be embedded with
270 * this player. Any such keywords should be added to the array.
272 * For example if this player supports FLV and F4V files then it should add
273 * '.flv' and '.f4v' to the array. (The check is not case-sensitive.)
275 * Default handling calls the get_supported_extensions function and adds
276 * a dot to each of those values, so players only need to override this
277 * if they don't implement get_supported_extensions.
279 * This is used to improve performance when matching links in the media filter.
281 * @return array Array of keywords to add to the embeddable markers list
283 public function get_embeddable_markers() {
285 foreach ($this->get_supported_extensions() as $extension) {
286 $markers[] = '.' . $extension;
292 * Gets the ranking of this player. This is an integer used to decide which
293 * player to use (after applying other considerations such as which ones
294 * the user has disabled).
296 * Rank must be unique (no two players should have the same rank).
298 * Rank zero has a special meaning, indicating that this 'player' does not
299 * really embed the video.
301 * Rank is not a user-configurable value because it needs to be defined
302 * carefully in order to ensure that the embedding fallbacks actually work.
303 * It might be possible to have some user options which affect rank, but
304 * these would be best defined as e.g. checkboxes in settings that have
305 * a particular effect on the rank of a couple of plugins, rather than
306 * letting users generally alter rank.
308 * Note: Within medialib.php, players are listed in rank order (highest
311 * @return int Rank (higher is better)
313 public abstract function get_rank();
316 * @return bool True if player is enabled
318 public function is_enabled() {
321 // With the class core_media_player_html5video it is enabled
322 // based on $CFG->core_media_enable_html5video.
323 $setting = str_replace('_player_', '_enable_', get_class($this));
324 return !empty($CFG->{$setting});
328 * Given a list of URLs, returns a reduced array containing only those URLs
329 * which are supported by this player. (Empty if none.)
330 * @param array $urls Array of moodle_url
331 * @param array $options Options (same as will be passed to embed)
332 * @return array Array of supported moodle_url
334 public function list_supported_urls(array $urls, array $options = array()) {
335 $extensions = $this->get_supported_extensions();
337 foreach ($urls as $url) {
338 if (in_array(core_media
::get_extension($url), $extensions)) {
346 * Obtains suitable name for media. Uses specified name if there is one,
347 * otherwise makes one up.
348 * @param string $name User-specified name ('' if none)
349 * @param array $urls Array of moodle_url used to make up name
350 * @return string Name
352 protected function get_name($name, $urls) {
353 // If there is a specified name, use that.
358 // Get filename of first URL.
360 $name = core_media
::get_filename($url);
362 // If there is more than one url, strip the extension as we could be
363 // referring to a different one or several at once.
364 if (count($urls) > 1) {
365 $name = preg_replace('~\.[^.]*$~', '', $name);
372 * Compares by rank order, highest first. Used for sort functions.
373 * @param core_media_player $a Player A
374 * @param core_media_player $b Player B
375 * @return int Negative if A should go before B, positive for vice versa
377 public static function compare_by_rank(core_media_player
$a, core_media_player
$b) {
378 return $b->get_rank() - $a->get_rank();
382 * Utility function that sets width and height to defaults if not specified
383 * as a parameter to the function (will be specified either if, (a) the calling
384 * code passed it, or (b) the URL included it).
385 * @param int $width Width passed to function (updated with final value)
386 * @param int $height Height passed to function (updated with final value)
388 protected static function pick_video_size(&$width, &$height) {
390 $width = CORE_MEDIA_VIDEO_WIDTH
;
391 $height = CORE_MEDIA_VIDEO_HEIGHT
;
398 * Base class for players which handle external links (YouTube etc).
400 * As opposed to media files.
402 * @copyright 2011 The Open University
403 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
405 abstract class core_media_player_external
extends core_media_player
{
407 * Array of matches from regular expression - subclass can assume these
408 * will be valid when the embed function is called, to save it rerunning
415 * Part of a regular expression, including ending ~ symbol (note: these
416 * regexes use ~ instead of / because URLs and HTML code typically include
417 * / symbol and makes harder to read if you have to escape it).
418 * Matches the end part of a link after you have read the 'important' data
419 * including optional #d=400x300 at end of url, plus content of <a> tag,
423 const END_LINK_REGEX_PART
= '[^#]*(#d=([\d]{1,4})x([\d]{1,4}))?~si';
425 public function embed($urls, $name, $width, $height, $options) {
426 return $this->embed_external(reset($urls), $name, $width, $height, $options);
430 * Obtains HTML code to embed the link.
431 * @param moodle_url $url Single URL to embed
432 * @param string $name Display name; '' to use default
433 * @param int $width Optional width; 0 to use default
434 * @param int $height Optional height; 0 to use default
435 * @param array $options Options array
436 * @return string HTML code for embed
438 protected abstract function embed_external(moodle_url
$url, $name, $width, $height, $options);
440 public function list_supported_urls(array $urls, array $options = array()) {
441 // These only work with a SINGLE url (there is no fallback).
442 if (count($urls) != 1) {
447 // Check against regex.
448 if (preg_match($this->get_regex(), $url->out(false), $this->matches
)) {
456 * Returns regular expression used to match URLs that this player handles
457 * @return string PHP regular expression e.g. '~^https?://example.org/~'
459 protected function get_regex() {
460 return '~^unsupported~';
464 * Annoyingly, preg_match $matches result does not always have the same
465 * number of parameters - it leaves out optional ones at the end. WHAT.
466 * Anyway, this function can be used to fix it.
467 * @param array $matches Array that should be adjusted
468 * @param int $count Number of capturing groups (=6 to make $matches[6] work)
470 protected static function fix_match_count(&$matches, $count) {
471 for ($i = count($matches); $i <= $count; $i++
) {
472 $matches[$i] = false;
479 * Player that embeds Vimeo links.
481 * @copyright 2011 The Open University
482 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
484 class core_media_player_vimeo
extends core_media_player_external
{
485 protected function embed_external(moodle_url
$url, $name, $width, $height, $options) {
486 $videoid = $this->matches
[1];
489 // Note: resizing via url is not supported, user can click the fullscreen
490 // button instead. iframe embedding is not xhtml strict but it is the only
491 // option that seems to work on most devices.
492 self
::pick_video_size($width, $height);
495 <span class="mediaplugin mediaplugin_vimeo">
496 <iframe title="$info" src="https://player.vimeo.com/video/$videoid"
497 width="$width" height="$height" frameborder="0"></iframe>
504 protected function get_regex() {
505 // Initial part of link.
506 $start = '~^https?://vimeo\.com/';
507 // Middle bit: either watch?v= or v/.
508 $middle = '([0-9]+)';
509 return $start . $middle . core_media_player_external
::END_LINK_REGEX_PART
;
512 public function get_rank() {
516 public function get_embeddable_markers() {
517 return array('vimeo.com/');
522 * Player that creates YouTube embedding.
524 * @copyright 2011 The Open University
525 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
527 class core_media_player_youtube
extends core_media_player_external
{
528 protected function embed_external(moodle_url
$url, $name, $width, $height, $options) {
529 $videoid = end($this->matches
);
532 if (empty($info) or strpos($info, 'http') === 0) {
533 $info = get_string('siteyoutube', 'core_media');
537 self
::pick_video_size($width, $height);
540 <span class="mediaplugin mediaplugin_youtube">
541 <iframe title="$info" width="$width" height="$height"
542 src="https://www.youtube.com/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
548 protected function get_regex() {
549 // Regex for standard youtube link
550 $link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
551 // Regex for shortened youtube link
552 $shortlink = '((youtu|y2u)\.be/)';
554 // Initial part of link.
555 $start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')';
556 // Middle bit: Video key value
557 $middle = '([a-z0-9\-_]+)';
558 return $start . $middle . core_media_player_external
::END_LINK_REGEX_PART
;
561 public function get_rank() {
562 // I decided to make the link-embedding ones (that don't handle file
563 // formats) have ranking in the 1000 range.
567 public function get_embeddable_markers() {
568 return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be');
574 * Player that creates YouTube playlist embedding.
576 * @copyright 2011 The Open University
577 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
579 class core_media_player_youtube_playlist
extends core_media_player_external
{
580 public function is_enabled() {
582 // Use the youtube on/off flag.
583 return $CFG->core_media_enable_youtube
;
586 protected function embed_external(moodle_url
$url, $name, $width, $height, $options) {
587 $site = $this->matches
[1];
588 $playlist = $this->matches
[3];
591 if (empty($info) or strpos($info, 'http') === 0) {
592 $info = get_string('siteyoutube', 'core_media');
596 self
::pick_video_size($width, $height);
599 <span class="mediaplugin mediaplugin_youtube">
600 <iframe width="$width" height="$height" src="https://$site/embed/videoseries?list=$playlist" frameborder="0" allowfullscreen="1"></iframe>
605 protected function get_regex() {
606 // Initial part of link.
607 $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
608 // Middle bit: either view_play_list?p= or p/ (doesn't work on youtube) or playlist?list=.
609 $middle = '(?:view_play_list\?p=|p/|playlist\?list=)([a-z0-9\-_]+)';
610 return $start . $middle . core_media_player_external
::END_LINK_REGEX_PART
;
613 public function get_rank() {
614 // I decided to make the link-embedding ones (that don't handle file
615 // formats) have ranking in the 1000 range.
619 public function get_embeddable_markers() {
620 return array('youtube');
626 * MP3 player inserted using JavaScript.
628 * @copyright 2011 The Open University
629 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
631 class core_media_player_mp3
extends core_media_player
{
632 public function embed($urls, $name, $width, $height, $options) {
633 // Use first url (there can actually be only one unless some idiot
634 // enters two mp3 files as alternatives).
637 // Unique id even across different http requests made at the same time
638 // (for AJAX, iframes).
639 $id = 'core_media_mp3_' . md5(time() . '_' . rand());
641 // When Flash or JavaScript are not available only the fallback is displayed,
642 // using span not div because players are inline elements.
643 $spanparams = array('id' => $id, 'class' => 'mediaplugin mediaplugin_mp3');
645 $spanparams['style'] = 'width: ' . $width . 'px';
647 $output = html_writer
::tag('span', core_media_player
::PLACEHOLDER
, $spanparams);
648 // We can not use standard JS init because this may be cached
649 // note: use 'small' size unless embedding in block mode.
650 $output .= html_writer
::script(js_writer
::function_call(
651 'M.util.add_audio_player', array($id, $url->out(false),
652 empty($options[core_media
::OPTION_BLOCK
]))));
657 public function get_supported_extensions() {
661 public function get_rank() {
668 * Flash video player inserted using JavaScript.
670 * @copyright 2011 The Open University
671 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
673 class core_media_player_flv
extends core_media_player
{
674 public function embed($urls, $name, $width, $height, $options) {
675 // Use first url (there can actually be only one unless some idiot
676 // enters two mp3 files as alternatives).
679 // Unique id even across different http requests made at the same time
680 // (for AJAX, iframes).
681 $id = 'core_media_flv_' . md5(time() . '_' . rand());
683 // Compute width and height.
685 if (!$width && !$height) {
686 $width = CORE_MEDIA_VIDEO_WIDTH
;
687 $height = CORE_MEDIA_VIDEO_HEIGHT
;
691 // Fallback span (will normally contain link).
692 $output = html_writer
::tag('span', core_media_player
::PLACEHOLDER
,
693 array('id'=>$id, 'class'=>'mediaplugin mediaplugin_flv'));
694 // We can not use standard JS init because this may be cached.
695 $output .= html_writer
::script(js_writer
::function_call(
696 'M.util.add_video_player', array($id, addslashes_js($url->out(false)),
697 $width, $height, $autosize)));
701 public function get_supported_extensions() {
702 return array('flv', 'f4v');
705 public function get_rank() {
712 * Embeds Windows Media Player using object tag.
714 * @copyright 2011 The Open University
715 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
717 class core_media_player_wmp
extends core_media_player
{
718 public function embed($urls, $name, $width, $height, $options) {
719 // Get URL (we just use first, probably there is only one).
720 $firsturl = reset($urls);
721 $url = $firsturl->out(false);
724 if (!$width ||
!$height) {
725 // Object tag has default size.
727 $size = 'width="' . CORE_MEDIA_VIDEO_WIDTH
.
728 '" height="' . (CORE_MEDIA_VIDEO_HEIGHT+
64) . '"';
731 $size = 'width="' . $width . '" height="' . ($height +
15) . '"';
732 $mpsize = 'width="' . $width . '" height="' . ($height +
64) . '"';
736 // MIME type for object tag.
737 $mimetype = core_media
::get_mimetype($firsturl);
739 $fallback = core_media_player
::PLACEHOLDER
;
743 <span class="mediaplugin mediaplugin_wmp">
744 <object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" $mpsize
745 standby="Loading Microsoft(R) Windows(R) Media Player components..."
746 type="application/x-oleobject">
747 <param name="Filename" value="$url" />
748 <param name="src" value="$url" />
749 <param name="url" value="$url" />
750 <param name="ShowControls" value="true" />
751 <param name="AutoRewind" value="true" />
752 <param name="AutoStart" value="false" />
753 <param name="Autosize" value="$autosize" />
754 <param name="EnableContextMenu" value="true" />
755 <param name="TransparentAtStart" value="false" />
756 <param name="AnimationAtStart" value="false" />
757 <param name="ShowGotoBar" value="false" />
758 <param name="EnableFullScreenControls" value="true" />
759 <param name="uimode" value="full" />
761 <object data="$url" type="$mimetype" $size>
762 <param name="src" value="$url" />
763 <param name="controller" value="true" />
764 <param name="autoplay" value="false" />
765 <param name="autostart" value="false" />
766 <param name="resize" value="scale" />
777 public function get_supported_extensions() {
778 return array('wmv', 'avi');
781 public function get_rank() {
788 * Media player using object tag and QuickTime player.
790 * @copyright 2011 The Open University
791 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
793 class core_media_player_qt
extends core_media_player
{
794 public function embed($urls, $name, $width, $height, $options) {
796 $firsturl = reset($urls);
797 $url = $firsturl->out(true);
800 if (!$width ||
!$height) {
801 $size = 'width="' . CORE_MEDIA_VIDEO_WIDTH
.
802 '" height="' . (CORE_MEDIA_VIDEO_HEIGHT +
15) . '"';
804 $size = 'width="' . $width . '" height="' . ($height +
15) . '"';
807 // MIME type for object tag.
808 $mimetype = core_media
::get_mimetype($firsturl);
810 $fallback = core_media_player
::PLACEHOLDER
;
814 <span class="mediaplugin mediaplugin_qt">
815 <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
816 codebase="http://www.apple.com/qtactivex/qtplugin.cab" $size>
817 <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
818 <param name="src" value="$url" />
819 <param name="controller" value="true" />
820 <param name="loop" value="false" />
821 <param name="autoplay" value="false" />
822 <param name="autostart" value="false" />
823 <param name="scale" value="aspect" />
825 <object data="$url" type="$mimetype" $size>
826 <param name="src" value="$url" />
827 <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
828 <param name="controller" value="true" />
829 <param name="loop" value="false" />
830 <param name="autoplay" value="false" />
831 <param name="autostart" value="false" />
832 <param name="scale" value="aspect" />
843 public function get_supported_extensions() {
844 return array('mpg', 'mpeg', 'mov', 'mp4', 'm4v', 'm4a');
847 public function get_rank() {
854 * Media player using object tag and RealPlayer.
856 * Hopefully nobody is using this obsolete format any more!
858 * @copyright 2011 The Open University
859 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
861 class core_media_player_rm
extends core_media_player
{
862 public function embed($urls, $name, $width, $height, $options) {
864 $firsturl = reset($urls);
865 $url = $firsturl->out(true);
867 // Get name to use as title.
868 $info = s($this->get_name($name, $urls));
870 // The previous version of this code has the following comment, which
871 // I don't understand, but trust it is correct:
872 // Note: the size is hardcoded intentionally because this does not work anyway!
873 $width = CORE_MEDIA_VIDEO_WIDTH
;
874 $height = CORE_MEDIA_VIDEO_HEIGHT
;
876 $fallback = core_media_player
::PLACEHOLDER
;
878 <span class="mediaplugin mediaplugin_real">
879 <object title="$info" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA"
880 data="$url" width="$width" height="$height"">
881 <param name="src" value="$url" />
882 <param name="controls" value="All" />
884 <object title="$info" type="audio/x-pn-realaudio-plugin"
885 data="$url" width="$width" height="$height">
886 <param name="src" value="$url" />
887 <param name="controls" value="All" />
898 public function get_supported_extensions() {
899 return array('ra', 'ram', 'rm', 'rv');
902 public function get_rank() {
909 * Media player for Flash SWF files.
911 * This player contains additional security restriction: it will only be used
912 * if you add option core_media_player_swf::ALLOW = true.
914 * Code should only set this option if it has verified that the data was
915 * embedded by a trusted user (e.g. in trust text).
917 * @copyright 2011 The Open University
918 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
920 class core_media_player_swf
extends core_media_player
{
921 public function embed($urls, $name, $width, $height, $options) {
922 self
::pick_video_size($width, $height);
924 $firsturl = reset($urls);
925 $url = $firsturl->out(true);
927 $fallback = core_media_player
::PLACEHOLDER
;
929 <span class="mediaplugin mediaplugin_swf">
930 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$width" height="$height">
931 <param name="movie" value="$url" />
932 <param name="autoplay" value="true" />
933 <param name="loop" value="false" />
934 <param name="controller" value="true" />
935 <param name="scale" value="aspect" />
936 <param name="base" value="." />
937 <param name="allowscriptaccess" value="never" />
939 <object type="application/x-shockwave-flash" data="$url" width="$width" height="$height">
940 <param name="controller" value="true" />
941 <param name="autoplay" value="true" />
942 <param name="loop" value="false" />
943 <param name="scale" value="aspect" />
944 <param name="base" value="." />
945 <param name="allowscriptaccess" value="never" />
958 public function get_supported_extensions() {
962 public function list_supported_urls(array $urls, array $options = array()) {
963 // Not supported unless the creator is trusted.
964 if (empty($options[core_media
::OPTION_TRUSTED
])) {
967 return parent
::list_supported_urls($urls, $options);
970 public function get_rank() {
977 * Player that creates HTML5 <video> tag.
979 * @copyright 2011 The Open University
980 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
982 class core_media_player_html5video
extends core_media_player
{
983 public function embed($urls, $name, $width, $height, $options) {
984 // Special handling to make videos play on Android devices pre 2.3.
985 // Note: I tested and 2.3.3 (in emulator) works without, is 533.1 webkit.
986 $oldandroid = core_useragent
::is_webkit_android() &&
987 !core_useragent
::check_webkit_android_version('533.1');
989 // Build array of source tags.
991 foreach ($urls as $url) {
992 $mimetype = core_media
::get_mimetype($url);
993 $source = html_writer
::tag('source', '', array('src' => $url, 'type' => $mimetype));
994 if ($mimetype === 'video/mp4') {
996 // Old Android fails if you specify the type param.
997 $source = html_writer
::tag('source', '', array('src' => $url));
1000 // Better add m4v as first source, it might be a bit more
1001 // compatible with problematic browsers.
1002 array_unshift($sources, $source);
1004 $sources[] = $source;
1008 $sources = implode("\n", $sources);
1009 $title = s($this->get_name($name, $urls));
1012 // No width specified, use system default.
1013 $width = CORE_MEDIA_VIDEO_WIDTH
;
1017 // Let browser choose height automatically.
1018 $size = "width=\"$width\"";
1020 $size = "width=\"$width\" height=\"$height\"";
1026 // Old Android does not support 'controls' option.
1027 $id = 'core_media_html5v_' . md5(time() . '_' . rand());
1028 $idtag = 'id="' . $id . '"';
1029 $sillyscript = <<<OET
1030 <script type="text/javascript">
1031 document.getElementById('$id').addEventListener('click', function() {
1038 $fallback = core_media_player
::PLACEHOLDER
;
1040 <span class="mediaplugin mediaplugin_html5video">
1041 <video $idtag controls="true" $size preload="metadata" title="$title">
1050 public function get_supported_extensions() {
1051 return array('m4v', 'webm', 'ogv', 'mp4');
1054 public function list_supported_urls(array $urls, array $options = array()) {
1055 $extensions = $this->get_supported_extensions();
1057 foreach ($urls as $url) {
1058 $ext = core_media
::get_extension($url);
1059 if (in_array($ext, $extensions)) {
1060 // Unfortunately html5 video does not handle fallback properly.
1061 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=10975
1062 // That means we need to do browser detect and not use html5 on
1063 // browsers which do not support the given type, otherwise users
1064 // will not even see the fallback link.
1065 // Based on http://en.wikipedia.org/wiki/HTML5_video#Table - this
1066 // is a simplified version, does not take into account old browser
1067 // versions or manual plugins.
1068 if ($ext === 'ogv' ||
$ext === 'webm') {
1069 // Formats .ogv and .webm are not supported in IE or Safari.
1070 if (core_useragent
::is_ie() || core_useragent
::is_safari()) {
1074 // Formats .m4v and .mp4 are not supported in Opera, or in Firefox before 27.
1075 // https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
1077 if (core_useragent
::is_opera() ||
(core_useragent
::is_firefox() &&
1078 !core_useragent
::check_firefox_version(27))) {
1089 public function get_rank() {
1096 * Player that creates HTML5 <audio> tag.
1098 * @copyright 2011 The Open University
1099 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1101 class core_media_player_html5audio
extends core_media_player
{
1102 public function embed($urls, $name, $width, $height, $options) {
1104 // Build array of source tags.
1106 foreach ($urls as $url) {
1107 $mimetype = core_media
::get_mimetype($url);
1108 $sources[] = html_writer
::tag('source', '', array('src' => $url, 'type' => $mimetype));
1111 $sources = implode("\n", $sources);
1112 $title = s($this->get_name($name, $urls));
1114 // Default to not specify size (so it can be changed in css).
1117 $size = 'width="' . $width . '"';
1120 $fallback = core_media_player
::PLACEHOLDER
;
1123 <audio controls="true" $size class="mediaplugin mediaplugin_html5audio" preload="no" title="$title">
1130 public function get_supported_extensions() {
1131 return array('ogg', 'oga', 'aac', 'm4a', 'mp3');
1134 public function list_supported_urls(array $urls, array $options = array()) {
1135 $extensions = $this->get_supported_extensions();
1137 foreach ($urls as $url) {
1138 $ext = core_media
::get_extension($url);
1139 if (in_array($ext, $extensions)) {
1140 if ($ext === 'ogg' ||
$ext === 'oga') {
1141 // Formats .ogg and .oga are not supported in IE or Safari.
1142 if (core_useragent
::is_ie() || core_useragent
::is_safari()) {
1146 // Formats .aac, .mp3, and .m4a are not supported in Opera.
1147 if (core_useragent
::is_opera()) {
1150 // Formats .mp3 and .m4a were not reliably supported in Firefox before 27.
1151 // https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
1152 // has the details. .aac is still not supported.
1153 if (core_useragent
::is_firefox() && ($ext === 'aac' ||
1154 !core_useragent
::check_firefox_version(27))) {
1158 // Old Android versions (pre 2.3.3) 'support' audio tag but no codecs.
1159 if (core_useragent
::is_webkit_android() &&
1160 !core_useragent
::is_webkit_android('533.1')) {
1170 public function get_rank() {
1177 * Special media player class that just puts a link.
1179 * Always enabled, used as the last fallback.
1181 * @copyright 2011 The Open University
1182 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1184 class core_media_player_link
extends core_media_player
{
1185 public function embed($urls, $name, $width, $height, $options) {
1186 // If link is turned off, return empty.
1187 if (!empty($options[core_media
::OPTION_NO_LINK
])) {
1191 // Build up link content.
1193 foreach ($urls as $url) {
1194 $title = core_media
::get_filename($url);
1195 $printlink = html_writer
::link($url, $title, array('class' => 'mediafallbacklink'));
1197 // Where there are multiple available formats, there are fallback links
1198 // for all formats, separated by /.
1201 $output .= $printlink;
1206 public function list_supported_urls(array $urls, array $options = array()) {
1207 // Supports all URLs.
1211 public function is_enabled() {
1212 // Cannot be disabled.
1216 public function get_rank() {