Передать на печать

Начала Metro-программирования: мультимедиа (ч.1)

Продолжаем знакомиться с возможностями платформы Metro. Эта программная платформа входит в состав Windows 8 и предназначена для разработки и исполнения нового класса приложений, рассчитанных на устройства с большим сенсорным экраном, - Metro-приложений.

Очередная статья будет посвящена разработке мультимедийных приложений, воспроизводящих звук и видео. Платформа Metro предоставляет для этого все необходимые инструменты: особые элементы интерфейса и программные средства. Они позволяют как собственно воспроизводить звук и видео, так и управлять их воспроизведением.

Внимание!
Перед чтением следует ознакомиться со статьями из цикла "Начала Metro-программирования", опубликованными на сайте ранее. Описанные в них приёмы программирования будут активно здесь использоваться.


1. Поддерживаемые форматы звука и видео
Windows 8 в изначальном комплекте поставки уже поддерживает большое количество форматов файлов и кодирования звука и видео. Давайте кратко перечислим поддерживаемые комбинации этих форматов.

Поддерживаемые комбинации форматов звука (указаны в виде <формат файлов> / <список форматов кодирования звука>):

  • MP3 / MP3;
  • WAV / PCM, MP3;
  • AC-3 / AC-3;
  • ADTS / AAC.


Поддерживаемые комбинации форматов видео со звуковым сопровождением (указаны в виде <формат файлов> / <список форматов кодирования звука> / <список форматов кодирования видео>):

  • AVI / MPEG IV Visual SP и ASP, Motion-JPEG, RAW / PCM, MP3, AC-3;
  • MPEG IV File / MPEG IV Visual SP и ASP, MPEG IV AVC / AAC, MP3;
  • MPEG II File / MPEG IV AVC / MPEG I Audio, MPEG II Audio, AC-3, AAC;
  • ASF / VC-1, WMV9 / WMA;
  • 3GP / MPEG IV Visual SP и ASP, MPEG IV AVC / AAC.


Звук и видео, являющееся частью интерфейса приложений, рекомендуется кодировать в форматах AAC и MPEG IV AVC соответственно и сохранять в файлах формата MPEG IV File. Кодировать звук в формате PCM и сохранять в файлах WAV, наоборот, не рекомендуется, так как подобные файлы имеют очень большие размеры.

Поддержка всех остальных форматов может быть добавлена установкой соответствующего программного обеспечения - кодеков и их наборов. Так, автор без проблем добавлял ещё в Windows 8 Developer Preview поддержку формата файлов Matroska, установив набор кодеков KLite Codec Pack.


2. Базовые средства поддержки мультимедиа
Начнём с рассмотрения рассмотрения базовых средств, которые позволят нам просто воспроизвести звуковой или видеофайл.

2.1. Воспроизведение звука
Для воспроизведения звука платформа Metro предоставляет особый элемент интерфейса - аудиопроигрыватель. Создаётся он средствами языка HTML - с помощью парного тега <audio>. Ссылка на сам звуковой файл и параметры его воспроизведения указываются в атрибутах данного тега; содержимого же он обычно не имеет.

<audio src="/media/sound.mp3" controls></audio>


Создаём аудиопроигрыватель для воспроизведения звукового файла sound.mp3, хранящегося в папке media, причём аудиопроигрыватель будет содержать элементы для управления воспроизведением.

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


Рис. 1. Аудиопроигрыватель с элементами для управления воспроизведением звукового файла


Уже понятно, что ссылка на сам звуковой файл указывается в атрибуте src тега <audio>. Это единственный обязательный атрибут данного тега.

Если в теге <audio> присутствует атрибут без значения controls, аудиопроигрыватель выведет на экран элементы для управления воспроизведением файла. В этом случае аудиопроигрыватель будет представлять собой блочный элемент интерфейса.

Если же атрибут тега controls не указывать, аудиопроигрыватель вообще не будет присутствовать на экране.

Указание атрибута тега без значения autoplay запустит загрузку и воспроизведение звукового файла сразу же после формирования элемента аудиопроигрывателя на экране. В противном случае файл сам загружаться и воспроизводиться не начнёт; воспроизведение должен запустить либо пользователь, либо само приложение — в коде логики. (Программное управление мультимедийными элементами интерфейса мы рассмотрим потом.)

Теперь предположим, что мы не желаем запускать воспроизведение звукового файла автоматически, но всё же хотим загрузить этот файл. Это может понадобиться, во-первых, чтобы в дальнейшем запустить его воспроизведение без задержки на загрузку, а во-вторых, чтобы сразу узнать его характеристики, в частности, продолжительность. Можно ли это сделать?

Можно. Нам поможет необязательный атрибут тега preload. Он может принимать три значения:

  • none — файл изначально загружаться не будет (поведение по умолчанию). Его загрузка начнётся только после того, как пользователь (либо само приложение) запустит его воспроизведение. В результате мы не сможем сразу же узнать характеристики файла, а его воспроизведение начнётся после задержки, необходимой для подгрузки достаточной порции мультимедийных данных.
  • metadata — будет загружена только заголовочная часть файла, хранящая сведения о нём. В результате мы сможем получить характеристики файла (как это сделать, будет рассказано потом), однако воспроизведение файла всё равно может начаться с задержкой.
  • auto — файл будет загружен целиком. В таком случае будут доступны сведения об этом файле, а его воспроизведение начёнется без задержки.


Понятно, что, если в теге <audio> присутствует атрибут autoplay, атрибут preload можно не указывать.

<audio src="/media/sound.mp3" controls preload="auto"></audio>


Осталось рассмотреть только атрибут тега без значения loop, который вызывает зацикливание звукового файла. По умолчанию файл будет воспроизведён всего один раз.

<audio src="/media/sound.mp3" autoplay controls loop></audio>


Как поётся в песне, эта музыка будет вечной...

2.2. Воспроизведение видео
Видео воспроизводится с помощью аналогичного элемента интерфейса - видеопроигрывателя. Он создаётся с помощью очень похожего тега <video>. Этот тег тоже является парным и тоже обычно не имеет содержимого, а все данные, необходимые для успешного воспроизведения видео, задаются в его атрибутах.

<video src="/movie.mp4" autoplay controls></video>


Создаём видеопроигрыватель для воспроизведения файла movie.mp4. При этом на экране будут присутствовать элементы управления его воспроизведением (см. рис. 2), а загрузка и воспроизведение файла начнутся сразу после формирования на экране элемента видеопроигрывателя.


Рис. 2. Видеопроигрыватель с элементами для управления воспроизведением видеофайла


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

Тег <video> поддерживает все атрибуты, знакомые нам по тегу <audio>: src, autoplay, controls, preload и loop.

Помимо этого, тег <video> поддерживает следующие необязательные атрибуты:

  • width — ширина видеопроигрывателя. Значение ширины указывается в виде целого числа в пикселах. Если ширина не задана, видеопроигрыватель будет иметь такую же ширину, как и постер (о постере — чуть позже); если постер отсутствует, он будет иметь ширину 300 пикселов.
  • height — высота видеопроигрывателя, также задаваемая в виде целого числа в пикселах. Если высота не указана, видеопроигрыватель будет иметь такую же высоту, как и постер, а если постер отсутствует — 150 пикселов.

    <video src="/movie.mp4" controls width="640" height="480"></video>

  • poster — ссылка на графический файл с постером, изображением, которое будет выводиться перед началом воспроизведения видеофайла. Если постер не указан, будет выведен первый кадр видеоролика.

    <video src="/movie.mp4" poster="/images/poster.jpg"></video>


2.3. Полноэкранное воспроизведение видео
Практически всегда приложение видеопроигрывателя воспроизводит видео, заполняя им весь экран устройства (полноэкранное воспроизведение). Как реализовать это в платформе Metro?

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

<селектор, удовлетворяющий элементу видеопроигрывателя> {
position: fixed;
width: 100%;
height: 100%;
}

Посмотрим, что он делает.

Атрибут стиля position устанавливает режим позиционирования элемента интерфейса, или, говоря другими словами, от чего будут отсчитываться его координаты. По умолчанию данный атрибут стиля имеет значение static, задающее обычный режим позиционирования элемента, когда его расположение зависит от того, в каком месте HTML-кода встретился тег, описывающий этот элемент. Значение fixed указывает другой режим позиционирования - когда положение элемента высчитывается относительно экрана устройства. Установка этого режима позволит нам точно совместить левую и верхнюю границы видеопроигрывателя с левой и верхней границами экрана.

Атрибуты стиля width и height указывают, соответственно, ширину и высоту элемента интерфейса. Понятно, что значение 100% растягивает элемент так, чтобы он занял всё пространство родителя (в нашем случае - экрана устройства) по ширине или высоте.

На заметку
Чтобы растянуть видеопроигрыватель на весь экран, можно применить также панель вывода Metro (см. предыдущие статьи этого цикла). Однако в этом случае возможно падение производительности при воспроизведении видео.


3. Программное управление воспроизведением мультимедиа
Аудиопроигрыватель HTML представляется объектом HTMLAudioElement, а видеопроигрыватель — объектом HTMLVideoElement. Эти объекты поддерживают большое количество свойств, методов и событий, с которыми мы сейчас познакомимся.

3.1. Свойства
Начнём с рассмотрения свойств объекта HTMLAudioElement:

  • src — хранит ссылку на воспроизводящийся мультимедийный файл в виде строки. Соответствует атрибуту тега src.
  • autoplay. Значение true указывает платформе Metro начать загрузку и воспроизведение файла сразу после формирования аудио- или видеопроигрывателя на экране, значение false — не делать этого. Соответствует атрибуту тега autoplay.
  • controls. Значение true указывает платформе Metro вывести на экран элементы для управления воспроизведением файла, значение false — не выводить их. Соответствует атрибуту тега controls.
  • loop. Значение true вызывает зацикливание файла, а значение false — его однократное воспроизведение. Соответствует атрибуту тега loop.
  • currentTime — хранит значение текущей позиции воспроизведения файла в виде числа с плавающей точкой в секундах. Присвоив этому свойству новое значение, мы можем переместить позицию воспроизведения в другое место ролика (выполнить его прокрутку).
  • volume — хранит значение текущей громкости в виде числа с плавающей точкой от 0 (звук совсем не слышен) до 1 (максимальная громкость; значение по умолчанию). С помощью этого свойства мы можем управлять громкостью воспроизведения звука.
  • muted. Значение true отключает звук, значение false — включает (поведение по умолчанию).
  • duration — возвращает продолжительность ролика в виде числа с плавающей точкой в секундах. Если продолжительность ролика ещё не удалось получить, возвращается значение NaN (Not a Number, "не число"). Для потоковых медиаресурсов возвращается значение Infinity (плюс бесконечность).
  • seeking — возвращает true, если в данный момент пользователь изменяет текущую позицию воспроизведения ролика (выполняет его прокрутку), и false во всех остальных случаях.
  • paused — возвращает true, если воспроизведение ролика приостановлено, и false, если оно продолжается.
  • ended — возвращает false, если воспроизведение ролики ещё продолжается, и true, если оно уже закончилось.


Объект HTMLVideoElement также поддерживает все эти свойства плюс ещё несколько специфических для видео; все эти свойства перечислены далее.

  • width — хранит ширину видеопроигрывателя в виде целого числа в пикселах. Соответствует атрибуту тега width.
  • height — хранит высоту видеопроигрывателя в виде целого числа в пикселах. Соответствует атрибуту тега height.
  • poster — хранит ссылку на файл с постером в виде строки. Соответствует атрибуту тега poster.
  • videoWidth — возвращает ширину изображения самого видеоролика в виде целого числа в пикселах. Если получить значение ширины невозможно (например, видеофайл не был загружен), возвращается 0.
  • videoHeight — возвращает высоту изображения самого видеоролика в виде целого числа в пикселах. Если получить значение высоты невозможно, возвращается 0.


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

var vidMain = document.getElementById("vidMain");
var iDuration = vidMain.duration;
var iWidth = vidMain.videoWidth;
var iHeight = vidMain.videoHeight;
vidMain.width = iWidth;
vidMain.height = iHeight;
vidMain.volume = 0.5;


Задаём для видеопроигрывателя размеры, соответствующие размерам изображения видеоролика, и половинное значение громкости.

3.2. Методы
Объекты HTMLAudioElement и HTMLVideoElement поддерживают всего два интересных для нас метода. Оба этих метода не принимают параметров и не возвращают результата.

  • play — начинает или возобновляет, если было приостановлено, воспроизведение ролика. Если для атрибута тега preload было задано значение none, вызов этого метода также инициирует загрузку файла.
  • pause — приостанавливает воспроизведение ролика.


vidMain.pause();


3.3. События
Объекты HTMLAudioElement и HTMLVideoElement поддерживают довольно много событий, которые могут быть для нас интересны. Мы рассмотрим их по группам.

К первой группе относятся события, возникающие в процессе загрузки звукового или видеофайла. Они возникают строго в том порядке, в котором перечислены далее.

  • loadstart — однократно возникает перед началом загрузки звукового или видеофайла.
  • durationchange — однократно возникает после того, как платформа Metro получит значение продолжительности загружаемого ролика.
  • loadedmetadata — однократно возникает после того, как платформа Metro получит значения ширины и высоты загружаемого видеоролика.
  • loadeddata — однократно возникает, когда объём загруженных мультимедийных данных становится достаточным для того, чтобы, по крайней мере, запустить воспроизведение ролика. Однако это ещё не гарантирует того, что ролик начнёт воспроизводиться без приостановок на подгрузку данных.
  • canplay — возникает всякий раз, когда объём загруженных мультимедийных данных становится достаточным для того, чтобы успешно начать или возобновить воспроизведение ролика. Но, опять же, это ещё не гарантирует того, что ролик впоследствии будет воспроизводиться без приостановок на подгрузку данных.
  • canplaythrough — возникает всякий раз, когда мультимедийные данные начинают загружаться со скоростью, достаточной для дальнейшего воспроизведения ролика без приостановок на их подгрузку.
  • progress — периодически возникает в процессе загрузки остальной части файла.
  • load — возникает после завершения загрузки файла.


Как видим, эти события позволяют довольно точно отследить все моменты, связанные с загрузкой мультимедийного файла.

Следующие события возникают в процессе воспроизведения ролика.

  • playing — однократно возникает сразу после начала или возобновления воспроизведения ролика. Воспроизведение может быть запущено либо самим пользователем, либо программно, вызовом метода play (см. ранее).
  • timeupdate — возникает всякий раз, когда текущая позиция воспроизведения ролика изменяется.
  • volumechanged — возникает при изменении уровня громкости, а также отключении и включении звука.
  • pause — возникает при приостановке воспроизведения ролика либо пользователем, либо программно, вызовом метода pause.
  • seeking — периодически возникает в процессе перемещения пользователем регулятора, указывающего текущую позицию воспроизведения ролика (прокрутке ролика). Этот регулятор входит в состав стандартных элементов управления воспроизведением, выводимых платформой Metro.
  • seeked — возникает после того, как пользователь переместит регулятор текущей позиции воспроизведения в новое положение.
  • waiting — возникает, если пользователь переместит регулятор текущей позиции воспроизведения в позицию, в которой воспроизведение невозможно из-за того, что необходимые мультимедийные данные ещё не загружены.
  • ended — возникает после завершения воспроизведения ролика.


События, перечисленные далее, возникают в случае появления проблем при загрузке файла. (Причиной этих проблем могут быть неполадки в работе сети, долговременной памяти устройства и т. п.)

  • error — возникает, если файл так и не удалось загрузить либо если данный файл имеет неподдерживаемый формат.
  • suspend — возникает всякий раз, когда мультимедийные данные временно перестают загружаться.
    Если загрузка данных успешно возобновляется, то снова последовательно возникают события canplay и canplaythrough, за которыми следует серия событий progress.
  • stalled — возникает через три секунды после загрузки последней порции мультимедийных данных. Как правило, возникновение этого события означает, что файл загрузить до конца не удастся.


var d = new Date(0, 0, 0, 0, 0, 0, 0);
var divPosition = document.getElementById("divPosition");
var iPos, s;
vidMain.addEventListener("timeupdate", function() {
  iPos = vidMain.currentTime;
  d.setHours(0, 0, iPos);
  s = d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
  divPosition.textContent = s;
});


Здесь мы привязываем к событию timeupdate видеопроигрывателя vidMain обработчик. Он будет выводить в специально созданном блоке divPosition текущую позицию воспроизведения фильма в привычном нам формате времени <часы>:<минуты>:<секунды>. Давайте подробно рассмотрим, как он работает.

Сначала мы создаём экземпляр объекта Date, хранящий "нулевое" значение даты и времени: нулевой год, нулевой месяц, нулевое число, ноль часов, ноль минут и ноль секунд. Это значение понадобится нам для преобразования значения текущей позиции воспроизведения, выраженного в секундах, в обычный формат времени, в котором мы и будем потом выводить это значение на экран.

В теле обработчика события timeupdate мы получаем текущую позицию воспроизведения. Выполняется это обращением к свойству currentTime нашего видеопроигрывателя.

Но как преобразовать это значение в обычный формат времени? Очень просто!

Объект Date поддерживает метод setHours, который позволяет задать для значения даты и времени новое время.

<значение даты и времени>.setHours(
  <часы>[,
  <минуты>[,
  <секунды>[,
  <миллисекунды>]]]
)

<миллисекунды>]]]
)[/code]
В качестве параметров этого метода указываются количества часов, минут, секунд и миллисекунд, которые и составят новое время; все эти параметры задаются в виде целых чисел. Причем обязательным является только количество часов; остальные параметры могут быть опущены. Результата метод setHours не возвращает.

Данный метод имеет интересную и крайне полезную особенность. Если мы зададим в качестве его параметра слишком большое количество, скажем, минут, он корректно преобразует их в часы. Так, если мы укажем 96 минут, то "на выходе" получим значение времени в 1 час и 36 минут. То же самое будет происходить с "лишними" часами, секундами и миллисекундами, которые будут переведены, соответственно, в дни, минуты и секунды.

Следовательно, указав в качестве третьего параметра метода значение текущей позиции воспроизведения в секундах, а в качестве значений остальных параметров — нули, мы получим это же значение, но уже выраженное в привычном для нас формате времени — в часах, минутах и секундах.

Напоследок нам останется только преобразовать полученное таким образом значение времени в строковый вид и вывести его на экран. Здесь нам пригодятся методы getHours, getMinutes и getSeconds объекта Date, возвращающие, соответственно, количество часов, минут и секунд, составляющих данное значение времени. А свойство textContent элемента интерфейса хранит его текстовое содержимое; присвоив этому свойству новое значение, мы выведем его таким образом на экран.

И ещё один момент. Для хранения промежуточных результатов вычисления в теле функции-обработчика мы используем не локальные переменные, а глобальные, объявленные вне тела этой функции. Тому есть две причины. Во-первых, объявление любой переменной отнимает определённое время. Во-вторых, после завершения выполнения тела функции локальные переменные должны быть удалены из памяти, и их удаление также отнимает время. В результате производительность нашего приложения снизится, что будет особенно заметно на маломощных бюджетных устройствах.


Дополнительные материалы


Окончание следует...

dronov_va, TheVista.Ru Team
Август 2012

  Передать на печать





Все права принадлежат © MSInsider.ru и TheVista.ru, 2013
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 1.1 (Страница создана за 0.063 секунд)