HTML5 INSIGHT


В продолжение темы работы с аудио и видео в HTML5 хочу остановиться на еще одном важном аспекте – программной вставке аудио и видео через JavaScript, и, если быть точнее, программном (через JavaScript) определении поддержки медиа-элементов и различных форматов и кодеков.

Хотя многие библиотеки добавляют свои обертки, упрощающую эту задачу, важно также понимать, что там происходит внутри.

Определение поддержки аудио и видео

Начнем с простой задачи: как понять, поддерживает ли браузер пользователя вставку аудио- и видео-элементов? 

Для решения этой задачи достаточно попытаться создать новый элемент с соответствующим тегом и посмотреть на результат:

var audio = document.createElement("audio");
// audio
/* [object HTMLAudioElement] {
autobuffer : false,
autoplay : false,
buffered : [object TimeRanges],
controls : false, currentSrc : "",
currentTime : 0,
defaultPlaybackRate : 1,
duration : NaN,
ended : false,
error : null ... }
*/

В случае, если браузер поддерживает аудио или видео-элементы, результатом создания нового элемента, согласно спецификации, должен быть объект типа HTMLAudioElement (HTMLVideoElement для видео).

audio instanceof HTMLAudioElement;
// true

(Если браузер поддерживает создание новых элементов, в том числе с произвольным названием, но не умеет поддерживать конкретный тип элемента, то результатом будет объект HTMLUnknownElement. Для старых браузеров это может быть не верно – и результатом будет объект какого-нибудь другого типа или просто Object с некоторыми свойствами, характерными для HTML-элементов.)

На этом этапе должно быть очевидно, что в принципе, достаточно через блок try-catch проверять поддержку браузером объекта HTMLAudioElement или HTMLVideoElement соответственно.

var videoSupported = false;
try {
HTMLVideoElement;
videoSupported = true;
} catch (e) {};
videoSupported;
// IE9 - true
// IE8 - false

Но если вы хотите использовать созданный медиа-элемент дальше, то пример, приведенный в начале, выглядит более практичным вследствие трюка, который мы увидим в следующем разделе. 

Определение поддержки формата/кодека

К этому моменту мы уже научились определять, поддерживает ли браузер медиа-элементы. Следующая возникающая проблема – понять, какие кодеки (форматы медиа-файлов) поддерживает браузер.

Напомню, что на сегодня эта картина весьма драматична и единого согласия хотя бы по одному общему формату для “аудио и для видео из коробки”, в общем-то, нет. В случае, если вы вставляете аудио или видео декларативно, вы можете сразу указать альтернативы, переложив задачу выбора на плечи самого браузера.

Чтобы решить эту задачу программно, в медиа-элементах есть специальный метод, общий для аудио и видео (формально, HTMLAudioElement и HTMLVideoElement оба реализуют интерфейс HTMLMediaElement), – canPlayType(), принимающий в качестве параметра строку описания типа медиа-файла.

var support = videoElement.canPlayType('video/x-new-fictional-format;codecs="kittens,bunnies"');

Если браузер знает, что он не поддерживает данный формат, например, из-за того, что он не умеет работать с указанным типом контейнера или нужного кодека нет в его списке поддерживаемых кодеков, – он должен вернуть пустую строку.

Пустая строка также возвращается, если в качестве типа указан “application/octet-stream” – общий mime-тип для бинарных файлов.

Если браузер уверен, что он сможет проиграть медиа-файл в заданном формате, он возвращает “probably”. В остальных случаях возвращается “maybe”.

Разница между “probably” и “maybe” может быть неочевидной, особенно с учетом близости значений двух слов (по крайней мере, в русском языке).

На языке спецификации, надо понимать два ключевых момента:

  1. И “probably” и “maybe” – это вероятностные вещи. Конечно, вы не получите числового выражения от 0 до 1 для каждого из этих значений, но важно понимать, что ни одно из них не равно 1.
  2. Ключевой момент различия между “probably” и “maybe” заключается в том, что если указан формат и известно, что для этого формата могут быть разные кодеки, но кодек не указан, браузер никогда не должен возвращать “probably” – он вернет “maybe”, так как могут быть комбинации кодеков, которые он не поддерживает.

Например, вот так это выглядит для IE9:

video.canPlayType('video/x-new-fictional-format;codecs="kittens,bunnies"'); 
// ""
video.canPlayType('video/mp4');
// "maybe"
video.canPlayType('video/mp4;codecs="avc1.42E01E, mp4a.40.2"');
// "probably"
video.canPlayType('video/mp4; codecs="avc1.58A01E, mp4a.40.2"');
// "probably"
video.canPlayType('video/mp4; codecs="mp4v.20.8, mp4a.40.2"');
// ""

Важная деталь, о которой важно помнить, заключается также в том, что сервер, который отдает вам медиа-файлы, должен быть корректно настроен, то есть отдавать видео и аудио с правильным mime-type. В противном случае, из соображений безопасности, браузер может блокировать работу с этими файлами.

Например, для IIS это можно проверить в панели управления и добавить недостающие форматы там же или через web.config:

<system.webServer>
<staticContent>
<mimeMap fileExtension=".mp4" mimeType="video/mp4" />
<mimeMap fileExtension=".m4v" mimeType="video/m4v" />
<mimeMap fileExtension=".webm" mimeType="video/webm" />
</staticContent>
</system.webServer>

Теперь, возвращаемся к обещанному трюку. Учитывая, что метод canPlayType есть только у медиа-элементов (в отличие от остальных типов элементов), его наличие является хорошим способом определить, что созданный элемент является именно медиа-элементом.

На практике проверку поддержки медиа-элементов и поддержки нужных форматов часто объединяют в общее выражение, которое к тому же оказывается короче, чем длинный поэтапный путь:

var audio = document.createElement("audio");
if (audio != null && audio.canPlayType && audio.canPlayType("audio/mpeg")){
audio.src = "audio/sample.mp3";
audio.play();
}

Наконец, давайте посмотрим, как проверка поддержка аудио и видео осуществляется через популярную библиотеку Modernizr. (Для любителей ASP.NET MVC напомню, что она также включена в состав  ASP.NET MVC 3.)

Использование Modernizr

Для начала, давайте я приведу внутренний код из библиотеки – исходя из изложенного выше, вам в нем практически все должно быть сходу понятно.

Проверка поддержки аудио-элемента и популярных кодеков:

tests['audio'] = function() {
var elem = document.createElement('audio'), bool = false;
try {
if ( bool = !!elem.canPlayType ) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"');
bool.mp3 = elem.canPlayType('audio/mpeg;');
bool.wav = elem.canPlayType('audio/wav; codecs="1"');
bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;');
}
} catch(e) { }
return bool;
};

 Проверка поддержки видео-элемента и популярных кодеков:

tests['video'] = function() {
var elem = document.createElement('video'), bool = false;
try {
if ( bool = !!elem.canPlayType ) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('video/ogg; codecs="theora"');
// Workaround required for IE9, which doesn't report video support without audio codec specified.
// bug 599718 @ msft connect
var h264 = 'video/mp4; codecs="avc1.42E01E';
bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"');
bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"');
}
} catch(e) { }
return bool;
};

(Про упоминаемый баг IE9 – надеюсь, в Modernizr это обновят, т.к. в финальной версии IE9 это давно поправлено.;)

Из приведенных примеров должен быть очевиден способ использования библиотеки для определения поддержки аудио/видео и соответствующих кодеков:

if (Modernizr.audio) {
var audio = new Audio();
audio.src = Modernizr.audio.mp3 ? 'background.mp3' :
             Modernizr.audio.ogg ? 'background.ogg' :            
                                   'background.m4a';
audio.play();
} else {
// Ooops.
}

Другие тонкости использования медиа-элементов HTML5 мы рассмотрим как-нибудь в другой раз ;)