UserJS для воспроизведения H.264 в «Опере»
Существует плагин «DivX web player», который отлично подменяет тег «VIDEO», в случае, если должен быть использован кодек H.264, но браузер его не поддерживает.
К сожалению, в «Опере» он почему-то не работает. Я сделал UserJS, который, пользуясь этим плагином, подменяет видеотег, если у него указан тип «video/mp4». Все атрибуты он не переносит (я просто пока не столкнулся с тем, что это нужно), буду добавлять, если столкнусь. Кроме того, я подменяю метод «canPlayType», чтобы показать, что браузер H.264 поддерживает.
Самая засада — это тег «VIDEO» без размеров. Мне для поддержки этого приходтся запускать проигрывание и когда становятся доступны медиаданные, останавливать воспроизведение и переписывать размеры видео.
// ==UserScript==
// @name XVid patch
// @author Evgeny Stepanischev aka Bolk
// @version 1.00
// @namespace /files/opera-xvid-patch.js
// @modified 2012-04-14
// @include http://*
// ==/UserScript==
!function () {
var htmlif = function (attr, attrname) {
return attr ? attrname + '="' + attr + '" ' : '';
}
var patchtag = function (o, src) {
var html = '<embed type="video/divx" '+
'custommode="none" ';
if (o.preload == 'auto') html += 'bufferingMode="full" '; else
if (o.preload == 'none') html += 'bufferingMode="null" ';
html += htmlif(o.poster, 'previewImage')+
htmlif(o.id, 'id')+
htmlif(o.name, 'name')+
htmlif(src || o.src, 'src')+
htmlif(o.controls ? 'full' : 'null', 'mode')+
htmlif(o.width, 'width')+
htmlif(o.height, 'height');
if (!o.height || !o.width) {
html += 'onloadedmetadata="this.width=this.videoWidth;this.height=this.videoHeight" ';
html += htmlif(!o.autoplay && 'if (!this._sized) {this.pause(); this.currentTime=0; this._sized=1}', 'onplay');
html += 'autoPlay=true ';
} else {
html += htmlif(o.autoplay ? 'true' : 'false', 'autoPlay');
}
html += 'pluginspage="http://go.divx.com/plugin/download/"></embed>';
o.outerHTML = html;
};
var patch = function () {
window.opera.addEventListener('BeforeScript', function() {
with (window.HTMLVideoElement)
if (prototype._canPlayType === undefined) {
prototype._canPlayType = prototype.canPlayType;
prototype.canPlayType = function (type) {
if (type.substr(0, 9) == 'video/mp4') {
return 'probably';
}
return this._canPlayType(type);
}
}
!function() {
var videos = document.getElementsByTagName('VIDEO');
for (var i = 0, vl = videos.length; i<vl; i++) {
if (!videos[i]) continue;
if (videos[i].type && videos[i].type.substr(0, 9) == 'video/mp4') {
} else {
var sources = videos[i].getElementsByTagName('source');
var foundSupported = false, foundMP4 = false;
for (var j = 0, sl = sources.length; j < sl; j++) {
if (videos[i]._canPlayType(sources[j].type) !== '') {
foundSupported = true;
break;
}
if (sources[j].type.substr(0, 9) == 'video/mp4') {
foundMP4 = sources[j].src;
}
}
if (!foundSupported && foundMP4) {
patchtag(videos[i], foundMP4);
}
}
}
}();
});
};
for (var i = 0, l = navigator.plugins.length; i < l; i++) {
if (navigator.plugins[i].filename == 'DivXBrowserPlugin.plugin') {
return patch();
}
}
}();
Добавлено: в комментариях справдливо указали на недостаток — перехватывать надо не только BeforeScript. Исправлять не буду до первого реального случая, когда где-то этого события не будет достаточно.
«быть» пропущено
Имеется ввиду формал «был», конечно. :)
А что означает конструкция !function(){}()? Та же ли это самовызывающаяся анонимная функция, что и (function(){})() и в чём смысл/особенность такой формы записи?
Комментарий для morozov.livejournal.com:
Да, это тоже самое. Фокус в восклицательном знаке: благодаря ему выходит функциональное выражение, а не определение функции. На один байт меньше скобок, и за ними не надо следить.
«для воспроизведения»
Ошибки поправил, спасибо всем!
Есть некоторые непонятки:
Комментарий для greli.livejournal.com:
Я нечасто пишу UserJS.
Глянул в доку, я думал это выполяется перед каждым выполнением скрипта (например, из событий). Надо переделать…
Нет, конечно. Потому что событие не дёрнется, пока основной JS не выполнится до конца. По сути _canPlayType определяется не до, а после. Сначала выполняется привязка события.
Это же неймспейс, а не УРЛ.
Комментарий для greli.livejournal.com:
Я пока решил ничего не трогать, до реальных проблем. Всё-таки это не решение, а костыль в какой-то мере. Надеюсь, что авторы DivX web player обратят внимание на «Оперу» и всё будет хорошо.
Комментарий для Евгения Степанищева:
Определение _canPlayType сделано внутри события и не произойдет до его вызова. Соответственно при первом вызове будет ошибка. Необходимо «with (window.HTMLVideoElement) ...» вынести за пределы определения события «window.opera.addEventListener(’BeforeScript’, function() { ...».
Комментарий для Treg:
Да, точно, надо просто поднять перед функцией. Видимо, правил код потом.
Комментарий для Treg:
Поправил, спасибо!
Комментарий для Евгения Степанищева:
Двумя годами ранее тоже правил ихний скрипт для использования под Оперой и заодно добавил поддержку для Windows Media компонента — http://habrahabr.ru/post/110794/ :)