Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript

Мультимедиа

Разбить на страницы
Показывать лекцию целиком

Файлы к данной лекции Вы можете скачать здесь.

Говорить, что средства аудиовизуальной информации важны для приложений – и для культуры в целом – это грубое преуменьшение. С тех пор, как люди, подобные Эдисону, сделали возможным записывать произведения для того, чтобы позже ими можно было насладиться, влечение человечества к мультимедийным данным – к изображениям, аудиозаписям, видеоклипам – возможно превысило тягу к автомобилям, электричеству и нездоровой пище. В ранние дни Интернета передача изображений легко занимала большую часть сетевого трафика. Сегодня, потоковое видео даже из одного отдельно взятого ресурса вроде Netflix поддерживает усилия по увеличению возможностей инфрастрктуры широкополосных сетей! (У меня дома это так и есть, с любимыми фильмами моего маленького сына вроде "Curious George", "Bob the Builder", "Dinosaur Train" и другими.)

Включение в себя, в той или иной форме, мультимедийной информации, это одна из основных забот большинства приложений для Магазина Windows. Простые, вероятно используют лишь несколько изображений для придания приложению фирменного стиля и отображения привлекательного пользовательского интерфейса, как мы уже видели много раз. Многие другие, особенно игры, конечно, используют и графику, и видео и аудио. В контексте этого курса все это поразумевает использование таких элементов HTML5, как img, svg (Scalable Vector Graphics – Масштабируемая векторная графика), canvas, audio и video.

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

  • Организация и правка медиафайлов, в том числе тех, что хранятся в библиотеках изображений, музыки и видео.
  • Конверсия (преобразование) медиафайлов, возможно, с применением различных фильтров и пользовательских кодеков.
  • Организация и правка плей-листов.
  • Захват аудио и видео с доступных устройств.
  • Потоковая передача данных с сервера на устройства, или с устройства на целевые объекты воспроизведений (PlayTo target), возможно, с применением DRM.
  • Эти возможности, для реализации которых существует множество API WinRT, вместе с мультимедиа-элементами HTML5 и их особыми возможностями в среде Windows 8, будут рассмотрены в этой лекции.

    Примечание. Обратите внимание на полный список аудио и видео-форматов, которые поддерживаются WinRT-приложениями: "Поддерживаемые форматы звука и видео" (http://msdn.microsoft.com/library/windows/apps/hh986969.aspx).

    Врезка: Трюки по повышению производительности для создания более быстрых приложений

    Некоторые из рекомендаций, данных в этой лекции, взяты из отличного выступления Джейсона Вебера, который занимается вопросами производительности Internet Explorer. Это выступление называется "50 трюков по повышению производительности, которые позволяют сделать ваше приложение для Windows 8, использующее HTML5, быстрее" (http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-386T). В то время, как некоторые из этих трюков имеют смысл для веб-приложений, которые исполняются в браузере, многие из них полностью применимы к приложениям для Магазина Windows, написанных на JavaScript, так как они исполняются на основе той же инфраструктуры, что имеется в Internet Explorer.

    Создание мультимедиа-элементов

    Конечно, самый простой способ включить мультимедийные данные в приложение – это то, что мы делаем уже многие годы: просто использовать подходящий HTML-элемент в разметке, и вуаля! – все сделано. С элементами img , audio, и video, на самом деле, вы без проблем можете исползовать содержимое из почти любого источника. То есть, атрибутам src этих элементов может быть назначены URI, которые указывают на содержимое в пакете приложения (с использованием относительных путей, URI ms-appx:/// , или путей, основанных на Windows.ApplicationModel.Package.current.installedLocation, которые затем передают в URL.createObjectURL), на файлы в папках данных приложения (с использованием URI ms-appdata:/// , или путей, основанных на Windows.Storage.ApplicationData.current с применением URL.createObjectURL), на удаленные файлы с применением http:// и других URI. В случае с элементом img сюда можно еще добавить использование в качестве источников SVG-файлов.

    Существуют три способа создания мультимедиа-элемента на странице или на элементе управления страницы:

    Во-первых, можно включить элемент напрямую в декларативный HTML-код. Часто полезно использовать атрибут preload="auto" для удаленного аудио или видео для увеличения скорости реакции элементов управления и других элементов пользовательского интерфейса, которые зависят от этих элеменов. (Это важно делать и для локальных медиафайлов, хотя они и так являются локальными!). Часто мультимедийные элементы размещают ближе к верхней части HTML-файла, в порядке приоритета, таким образом, их загрузка может начаться уже в то время, когда остальные части документа еще обрабатываются.

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

    Воспроизведение для элементов, заданных декларативно, может быть начато автоматически, благодаря атрибуту autoplay, посредством встроенного пользовательского интерфейса, если элемент имеет атрибут controls, или с помощью вызова из JavaScript команды <element>.play().

    Второй метод заключается в создании HTML-элемента в JavaScript посредством document.createElement и в добавлении его в DOM с помощью команды <parent>.appendChild и похожих методов. Вот пример использования мультимедиа-файлов, который находится в дополнительных материалах к этой лекции, хотя вам нужно поместить этот код в новый собственный проект:

     //Создаем элемент и добавляем его в DOM, что приведет к изменению макета
    var picture = document.createElement("img");	
    picture.src = "media/wildflowers.jpg";	
    picture.width = 300;	
    picture.height = 450;	
    document.getElementById("divShow").appendChild(picture);	
    
    var movie = document.createElement("video");
    movie.src = "media/ModelRocket1.mp4"; 
    movie.autoplay = false;
    movie.controls = true;
    document.getElementById("divShow").appendChild(movie);
    
    var sound = document.createElement("audio");	
    sound.src = "media/SpringyBoing.mp3";	
    sound.autoplay = true; //Запускаем проигрывание как только элемент будет добавлен в DOM	
    sound.controls = true; //Если установлено false, аудио проигрывается, но не влияет на макет
    document.getElementById("divShow").appendChild(sound);
    

    Если элементы для вывода изображений или видео не скрыты с помощью стилей, а так же, если речь идет об элементах с установленным атрибутом controls, то их добавление вызывает повторную отрисовку макета документа. Аудио-элемент без данного атрибута не приводит к повторному выводу макета. Как и в декларативном HTML, установка аutoplay в значение true приведет к запуску воспроизведения видео или аудио сразу после того, как элемент будет добавлен в DOM.

    И, наконец, для аудио, приложения могут создавать объект Audio в JavaScript для проигрывания звуков или музыки без какого-либо воздействия на пользовательский интерфейс. Больше об этом будет позже. В JavaScript так же есть класс Image, класс Audio может быть использован для загрузки видео:

    //Создаем объекты (с предварительной загрузки), затем нужным образом задаем источники других DOM-объектов	
    var picture = new Image(300, 450);	
    picture.src = "http://www.kraigbrockschmidt.com/downloads/media/wildflowers.jpg";
    
    document.getElementById("image1").src = picture.src;	
    
    //Объект Audio можно использовать для предварительной загрузки 
    (но не воспроизведения) видео
    var movie = new Audio("http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4");
    document.getElementById("video1").src = movie.src;
    
    var sound = new Audio("http://www.kraigbrockschmidt.com/downloads/media/SpringyBoing.mp3");
    document.getElementById("audio1").src = sound.src;
     

    Создание объектов Image или Audio из кода не приводит к созданию элементов в DOM, что может быть полезным. Объект Image, например, многие годы используется для предварительной загрузки массивов исходных изображений для использования в задачах наподобие вращения изображений или при реализации всплывающих меню. Предварительная загрузка в данном случае означает лишь то, что изображения были загружены и кэшированы. Таким образом, присваивание того же самого URI атрибуту SRC элемента, который уже находится в DOM, как показано выше, приведет к немедленному появлению изображения. То же самое справедливо для предварительно загруженного видео и аудио, но, опять же, это, в первую очередь, полезно для использования с удаленными источниками, в то время, как файлы из локальной файловой системы загружаются сравнительно быстро и без дополнительных усилий с нашей стороны. Тем не менее, если у вас есть большие локальные изображения, и вы хотите быстро показать их, когда они понадобятся, предварительная загрузка их в па мять – это полезная стратегия.

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

    Графические элементы: Img, Svg и Canvas (и немного CSS)

    Знаю, вам, вероятно, не терпится прочесть разделы этой лекции, посвященные аудио и видео, но мы не можем забывать о том, что изображения были основой веб-приложений с самого начала и их важность в реализации опыта взаимодействия пользователя и приложения все еще огромна. Действительно, полезно помнить о том, что видео, концептуально, это лишь последовательный набор статических изображений, быстро сменяющих друг друга! К счастью, HTML5 значительно расширил возможность приложений по включению в себя графических данных путем добавления поддержки формата SVG и элемента canvas к проверенному временем элементу управления img. Кроме того, применение CSS-анимаций и переходов (этому посвящена лекции 7-8) к элементам изображений, которые иначе неподвижны, позволяет сделать их очень динамичными.

    Говоря о CSS, важно отметить, что многие графические эффекты, которые раньше требовали применения соответствующим образом подготовленного статического изображения, могут быть реализованы только с использованием CSS, в частности, с применением CSS3:

  • Границы, фоновые цвета, фоновые изображения.
  • Изображения закладок папок, меню, панели инструментов.
  • Скругленные углы границ, использование нескольких границ и фонов, границы изображений
  • Прозрачность
  • Встраиваемые шрифты
  • Тени объектов
  • Тени текстов
  • Градиенты
  • Коротко говоря, если вы когда-либо использовали элементы ) от Smashing Magazine и к спецификациям CSS3 на http://www.w3.org/. CSS так же предоставляет возможность декларативно обрабатывать некоторые события и визуальные состояния с использованием псевдо-селекторов для и к еще материалу Smashing Magazine по псевдо-классам (http://coding.smashingmagazine.com/2011/03/30/how-to-use-css3-pseudo-classes/).

    Рассмотрим теперь три основные HTML5-элемента для вывода изображений:

  • Элемент img используется для растровых изображений. Формат PNG предпочтителен по сравнению с другими, особенно для текстов и штриховых рисунков, хотя JPEG-файлы фотографий имеют меньший размер. GIF, как правило, считается устаревшим, в тех случаях, когда использование GIF-файлы давало выигрыш за счет маленького размера, теперь можно пользоваться исключительно CSS. Если речь идет о масштабировании, приложения для Магазина Windows должны учитывать плотность пикселей, как мы видели в лекции 6 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", и предоставлять различные файлы изображений ля каждого масштаба, с которым может столкнуться приложение. Это тот случай, когда JPEG-файлы меньшего размера могут уменьшить общий размер пакета приложения в Магазине Windows.
  • Формат SVG лучше всего использовать для плавного масштабирования изображений на мониторах разного размера и разной плотности пикселей. SVG-изображения могут быть описаны внутри HTML-кода, созданы динамически в DOM, ими можно управлять как отдельными файлами и использовать в качестве источника для элемента img (в этом случае все характеристики масштабирования поддерживаются). SVG-файл так же может быть использован как источник для iframe, что дает преимущества в виде доступности дочерних элементов SVG в DOM. Как мы видели в лекции 6 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", сохранение соотношения сторон SVG-изображения часто важно, для чего мы использовали viewBox и атрибуты preserveAspectRatio тега svg.
  • Элемент canvas (холст) предоставляет поверхность для рисования и API для создания изображений с использованием линий, прямоугольников, дуг, текста и так далее. Холст, в итоге, генерирует растровые данные, что означает, что будучи однажды созданным, такое изображение масштабируется как растровое. (Приложение, конечно, обычно перерисовывает холст с масштабированием координат для того, чтобы избежать пикселизации). Холст весьма полезен для выполнения манипуляций с пикселями, даже с отдельными кадрами видео, когда оно проигрывается.
  • Приложения часто используют все три элемента, опираясь на их сильные стороны. Я говорю это, так как, когда элемент canvas впервые стал доступен, разработчики оказались так им очарованы, что, казалось, забыли, как пользоваться img и они игнорируют тот факт, что часто SVG – это наилучший вариант! (И я ведь уже сказал, что CSS сам по себе способен на многое, а?)

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

    Что отличает эти элементы друг от друга, так это то, как в них поступают данные. Элементы img загружают данные из файла-источника, svg-данные заданы в разметке, элементы canvas заполняются посредством программного кода. Но, в конце концов, как показано в Сценарии 1 упражнения "Графика в HTML" для этой лекции, и как отражено на рис. 5.1 все они производят одинаковые результаты: (рис 5.1) Элементы img, canvas и svg показывают одинаковый результат

    Коротко говоря, в том, что может быть выведено с помощью каждого из элемента, нет фундаментальных различий. Тем не менее, у них есть различия, которые становятся очевидными, когда мы начинаем манипулировать этими элементами как и в случае с CSS. Так каждый элемент – это лишь узел в DOM, простой и ясный, и они рассматриваются как и все другие, неграфические элементы: CSS не влияет на внутреннее содержимое элементов, а влияет лишь на то, как они, в итоге, отображаются на странице. Отдельные части SVG, объявленные в разметке, могут, на самом деле, быть отдельно стилизованы до тех пор, пока их можно идентифицировать с помощью CSS-селекторов. В любом случае, подобная стилизация влияет только на внешний вид, таким образом, если применяются новые стили, они применяются к исходному содержимому элемента.

    Справедливо и то, что графические элементы могут перекрывать друг друга и неграфические элементы (как и видео), и подсистема визуализации автоматически обрабатывает прозрачность в соответствии с параметром z-index этих элементов. Каждый графический элемент может иметь чистые, или прозрачные области, которые встроены в форматы изображений наподобие PNG. В элементе canvas, любые области, очищенные с помощью метода clearRect, которые иным образом не затрагивают другие вызовы API, будут прозрачными. Похожим образом, любая область прямоугольного элемента SVG, которая не затронута его отдельными частями, будет прозрачной.

    Сценарий 2 в упражнении "Графика в HTML" позволяет вам включать несколько стилей (с помощью флагов) для тех же элементов, которые показаны ранее. В данном случае я сделал фон элемента canvas прозрачным, таким образом, мы можем видеть то, что распложено за ним. Когда стили применяются, элемент img оказывается повернутым и трансформированным, к canvas применяется масштабирование, и отдельные части svg-элемента стилизуются новыми цветами, как показано на рис. 5.2. (рис 5.2) Стили, примененные к графическим элементам; отдельные элементы SVG могут быть стилизованы, если они доступны посредством DOM

    Стили, заданные в css/scenario2.css, довольно просты:

    .transformImage {
    transform: rotate(30deg) translateX(120px);
    }
    
    .scaleCanvas {
    transform: scale(1.5, 2);
    }
     

    Как и код в js/scenario2.js, который их применяет:

    function toggleStyles() {
    var applyStyles = document.getElementById("check1").checked;
    
    document.getElementById("image1").className = applyStyles ? "transformImage" : "";
    document.getElementById("canvas1").className = applyStyles ? "scaleCanvas" : "";
    
    document.getElementById("r").style.fill = applyStyles ? "purple" : "";	
    document.getElementById("l").style.stroke = applyStyles ? "green" : "";	
    document.getElementById("c").style.fill = applyStyles ? "red" : "";	
    document.getElementById("t").style.fontStyle = applyStyles ? "normal" : "";	
    document.getElementById("t").style.textDecoration = applyStyles ? "underline" : "";
     }	
     

    Другая особенность, которую вы могли заметить при применении стилей, это то, что увеличенный элемент canvas выглядит пикселизованным, как обычно бывает с растровыми изображениями. Это вполне ожидаемое поведение, как показано в следующей таблице о характеристиках масштабирования. Это показано в Сценариях 3 и 4 упражнения "Графика в HTML".

    Элемент Масштабирование Обработка изменений макета для лучшего отображения
    img растеризованное Измените атрибут src для различных масштабов (или просто используйте SVG-файл в качесте источника).
    canvas растеризованное Перерисуйте холст с использованием масштабированных размеров; часто это можно сделать наилучшим образом, вызвав <context>.scale в соответствии с необходимым размером отображения вместо изменения координат, использованных в коде
    svg плавное Нет необходимости. Используйте viewBox и preseveAspectRatio для пропорционального изменения масштаба.

    Дополнительные характеристики графических элементов

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

    Элемент Операции, вызывающие перерисовку Режим Преимущества
    img Изменение атрибута src Изменение стиля из JavaScript Пиксельный

    Быстро выводится и трансформируется

    Отлично подходит для статических элементов и статических/повторяющихся фонов

    Возможна спрайтовая анимация путем изменения атрибута src

    canvas

    Вызов контекстного API

    Изменение стиля из JavaScript

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

    Немедленный: вызовы API приводят к выводу пикселей и не запоминаются

    Качественный динамический контент

    Быстро выводится после перерисовки

    Возможность манипуляции изображением на уровне пикселей

    Отлично подходит для качественного динамического/интерактивного содержимого с частым использованием вычислений.

    svg

    Изменение структуры элемента

    Изменение стиля из JavaScript

    С запоминанием: все фигуры существуют как элементы DOM (если не используется в атрибуте img src)

    Плавное масштабирование

    Точное управление отдельными (запоминаемыми) элементами

    Возможность манипуляции на уровни фигур

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

    Так как SVG создает элементы в DOM, эти элементы могут быть стилизованы индивидуально. Вы можете использовать этот факт вместе с медиа-запросами для скрывать разные части SVG в зависимости от их размера. Для того, чтобы сделать ээто, добавьте различные классы к таким SVG-элементам, затем, в CSS, добавьте или удалите стиль display: none для этих классов в медиа-запросах наподобие @media (min-width:300px) and (max-width:499px) . Вам может понадобиться рассчитать размер SVG по отношению к окну приложения, но это означает, что вы можете эффективно убрать детали из SVG вместо того, чтобы позволять этим частям отрисовываться на слишком малом пространстве, чтобы быть полезными.

    В итоге, причина по которой HTML5 имеет все три элемента, заключается в том, что все три по-настоящему нужны. Все они способны получить преимущества от полного аппаратного ускорения, так же, как это происходит в Internet Explorer, так как приложения, написанные на HTML и JavaScript исполняются на той же подсистеме визуализации, что и браузер.

    Лучший подход к дизайну приложений – по-настоящему исследовать подходящие варианты использования элементов каждого типа. Каждый элемент может иметь прозрачные области, в итоге, вы можете легко достигнуть весьма забавных эффектов. Например, если у вас есть данные, которые выводят временную информацию о видео или другой текст, в надпись, вы можете просто использовать обработчик интервалов (с интервалом, установленным на необходимую детализации, пол секунды, например), получить свойство видео currentTime, получить необходимый текст для данного фрагмента, и вывести текст на пэлементе canvas c прозрачным фоном, который расположен поверх видео. Субтитры и другие сведения о видео можно вывести похожим образом, устраняя необходимость в перекодировании видео.

    Некоторые советы и секреты

    Работа с графическими элементами HTML5 довольно проста, но знание некоторых подробностей может помочь в работе с ними в приложениях для Магазина Windows.

    Элементы Img

  • Используйте атрибут title элемента img для реализации всплывающей подсказки, а не атрибут alt. так же вы можете использовать элемент управления WInJS.UI.Tooltip, как показано в лекции 4 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript".
  • Для создания изображений из потока, расположенного в памяти, воспользуйтесь методом ), результат его работы затем можно передать в URL.createObjectURL для создания подходящего для атрибута src URL. Мы встретимся с этим в данной лекции, и нам это понадобится при работе с контрактом "Общий доступ" в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Та же техника работает для аудио и видео-потоков.
  • Загружая изображение из http:// или с другого удаленного источника, вы рискуете столкнуться с отображением в элементе изображения-заполнителя с красным значком "X". Для того, чтобы предотвратить это, перехватите событие img.onerror и предоставьте собственный элемент-заполнитель:
    var myImage = document.getElementById('image');
    myImage.onerror = function () { onImageError(this);}
    function onImageError(source) {	
    source.src = "placeholder.png";
    source.onerror = "";	
    }	
     
  • Элементы SVG

  • Теги <script> не поддерживаются внутри <svg> .
  • Если у вас есть SVG-файл, вы можете загрузить его в элемент img, сославшись на файл в атрибуте src, но это не позволит вам обходить SVG в DOM. Если вам нужно подобное поведение, загрузите SVG в iframe. Содержимое SVG тогда будет расположено внутри свойства contentDocument.documentElement:
    <!-- В HTML-->
    <iframe id="Mysvg" src="myFolder/mySVGFile.svg" />
    
    // В JavaScript
    var svg = document.getElementById("Mysvg").contentDocument.documentElement;
     
  • Файлы в форматах PNG и JPEG обычно обрабатываются быстрее, чем SVG, поэтому, если технической необходимости в использовании SVG нет, или если вы имеете дело со сценарием, требующем высокой производительности, рассмотрите вариант использования масштабированных растровых изображений. Или вы можете динамически создавать масштабированные статические изображения из SVG для того, чтобы использовать их позже для более быстрого рендеринга:
    <!-- В HTML-->
    <img id="svg" src="somesvg.svg" style="display: none;" />
    <canvas id="canvas" style="display: none;" />
    // В JavaScript	
    var c = document.getElementById("canvas").getContext("2d");	
    c.drawImage(document.getElementById("svg"),0,0);	
    var imageURLToUse = document.getElementById("canvas").toDataURL();
    
  • Вот два полезных материала по SVG: http://www.carto.net/papers/svg/samples/ и http://srufaculty.sru.edu/david.dailey/svg/.
  • Элементы Canvas

    Все упомянутые здесь имена фукнций – это методы объекта контекста canvas:

  • Помните, что элемент canvas нуждается в задании атрибутов width и height (в JavaScript – canvas.width и canvas.height), а не стилей. Он не принимает таких единиц измерения, как px, em, % и других.
  • Несмотря на имя, метод closePath не является прямым дополнением метода beginPath. Метод beginPath используется для создания нового контура, который может быть обведен линией, сбрасывая существующий контур. Метод closePath, с другой стороны, просто соединяет две конечных точки текущего контура, как если бы вы исполнили для этих точек команду lineTo. Он не сбрасывает контур и не создает новый. Это часто вызывает у программистов путаницу, и поэтому иногда можно видеть окружности, нарисованные с линией, проведенной к их центру!
  • Вызов stroke необходим для отрисовки контура, до этого вы можете рассматривать его как карандашный набросок чего-либо, который пока не закрашен тушью. Обратите так же внимание на то, что обведение контура означает вызов beginPath.
  • При анимации содержимого canvas, выполнение clearRect для всего элемента и перерисовка каждого кадра обычно легче реализуема, чем очищение множества небольших областей и перерисовывание отдельных частей элемента. Хост-процесс приложения, в итоге, выполняет рендеринг всего элемента, со всем его содержимым, для каждого кадра, в целях управления прозрачностью, поэтому попытка оптимизировать производительность путем очищения небольших областей – это неэффективная стратегия, за исключением случаев, когда вы выполняете небольшое количество вызовов API для каждого кадра.
  • API отрисовки элемента canvas реализованы путем конверсии его в соответствующие вызовы Direct2D GPU. При таком подходе фигуры выводятся с автоматическим антиалиасингом. В результате, рисование фигуры, наподобие незаполненной окружности, и рисование той же окружности с заданным фоновым цветом, не приводит к очистке каждого пикселя. Для того, чтобы эффективно очистить пиксели, используйте команду clearRect для области, которая немного больше, чем фигура. Это одна из причин, по которой очистка всего элемента и перерисовка каждого кадра часто оказывается самым простым решением.
  • Для того чтобы задать в элементе canvas фоновое изображение (то есть, вам не придется каждый раз его перерисовывать), вы можете использовать свойство canvas.style.backgroundImage с подходящим URI для изображения
  • Используйте метод ) для объекта ) для содержимого элемента.
  • При использовании drawImage, вам может понадобиться подождать какое-то время, пока необходимое изображение загрузится с использованием подобного кода:
     var img = new Image();
    img.onload = function () { myContext.drawImage(myImg, 0, 0); }
    myImg.src = "myImageFile.png";
    
  • Хотя другие графические API видят окружность как особый случай эллипса (с одними и теми же параметрами радиусов x и y), функция arc элемента canvas работает только с окружностями. К счастью, небольшое использование масштабирования упрощает рисование эллипсов, как показано ниже. Обратите внимание на то, что мы используем команды save и restore, таким образом, команда scale применяется только к arc. Она не воздействует на stroke, который используется из main. Это важно, так как если показатель масштабирования все еще действует, когда вы вызываете stroke, ширина линии будет меняться вместо того, чтобы оставаться постоянной.
    var img = new Image();
    img.onload = function () { myContext.drawImage(myImg, 0, 0); }
    myImg.src = "myImageFile.png";
    function arcEllipse(ctx, x, y, radiusX, radiusY, startAngle, endAngle, anticlockwise) {
    //Используем меньший радиус как базу и растягиваем другой	
    
    var radius = Math.min(radiusX, radiusY);	
    var scaleX = radiusX / radius;	
    var scaleY = radiusY / radius;	
    ctx.save();
    ctx.scale(scaleX, scaleY);
    
    //Обратите внимание на то, что центральная точка должна учитывать масштабирование	
    ctx.arc(x / scaleX, y / scaleY, radius, startAngle, endAngle, anticlockwise);
    ctx.restore();	
    }	
     
  • Копируя пиксельные данные из видео, возможно с использованием canvas динамически манипулировать видеоданными (не влияя на источник, конечно). Это полезная техника, даже учитывая то, что она интенсивно использует процессор. По этой причине, однако, такой подход может не работать нормально на маломощных устройствах.
  • Вот пример покадровой манипуляции с видео, техника, которая отлично освещена в блоге команды разработки Windows, в сообщение "Прямая манипуляция пикселями в canvas"Кроме того, обратитесь к материалу http://beej.us/blog/data/html5s-canvas-2-pixel/ (http://blogs.windows.com/windows/archive/b/developers/archive/2011/02/15/canvas-direct-pixel-manipulation.aspx). В упражнении к этой лекции VideoEdit, файл default.html содержит в теле элементы video и canvas:

    <video id="video1" src="ModelRocket1.mp4" muted style="display: none"></video>
    <canvas id="canvas1" width="640" height="480"></canvas>
    

    В коде (js/default.js), мы вызываем функцию startVideo из обработчика активации. Эта функция запускает воспроизведение видео и использует requestAnimationFrame для выполнения пиксельной манипуляции для каждого видеокадра:

    function startVideo() {	
    video1 = document.getElementById("video1");	
    canvas1 = document.getElementById("canvas1");
    ctx = canvas1.getContext("2d");	
    
    video1.play();
    requestAnimationFrame(renderVideo);
    }
    
    function renderVideo() {
    //Копируем кадр из видео в canvas 
    ctx.drawImage(video1, 0, 0, canvas1.width, canvas1.height);
    
    //Получаем кадр в виде пиксельных данных
    var imgData = ctx.getImageData(0, 0, canvas1.width, canvas1.height);
    var pixels = imgData.data;
    
    //Обходим пиксели, обрабатывая их так, как нам нужно 
    var r, g, b;
    
    for (var i = 0; i < pixels.length; i += 4) {
    r = pixels[i + colorOffset.red];	
    g = pixels[i + colorOffset.green];	
    b = pixels[i + colorOffset.blue];	
    
    // Здесь создается негативное изображение	
    pixels[i + colorOffset.red] = 255 - r;	
    pixels[i + colorOffset.green] = 255 - g;
    pixels[i + colorOffset.blue] = 255 - b;	
    }	
    
    //Копируем измененные пиксели в canvas
    ctx.putImageData(imgData, 0, 0);
    //Запрашиваем следующий кадр
    requestAnimationFrame(renderVideo);
    }
     

    Страница в этом примере содержит скрытый видеоэлемент (style="display: none"), в котором запускается воспроизведение при загрузке страницы (video1.play()). В цикле requestAnimationFrame, текущий кадр из видео копируется в canvas (drawImage) и пиксели кадра копируются (getImageData) в буфер imgData. Затем мы обходим этот буфер и инвертируем цветовую информацию, создавая, таким образом, фотографический негатив изображения (альтернативная формула для перевода изображения в цветовой режим оттенков серого показана в комментариях и опущена выше). Затем мы копируем полученные пиксели обратно в canvas (putImageData), таким образом, когда мы возвращаемся, негатив изображения выводится на экран.

    Повторюсь, подобные операции интенсивно используют процессор и обычно не подлежат ускорению с помощью GPU, то есть, могут выполняться не очень хорошо на маломощных устройствах (однако, не забудьте запустить Release build (построении Выпуска) программы за пределами отладчика для оценки производительности). Гораздо лучше будет написать DLL для реализации видеоэффектов, там, где это возможно, как обсуждается в разделе "Применение видеоэффектов" ниже. Тем не менее, об этой технике полезно знать. Что на самом деле происходит, так это то, что вместо рисования каждого кадра с помощью вызовов API, мы просто используем видео в качестве источника данных. Мы можем, если захотим, украсить canvas любым другим способом, прежде чем возвращаться из функции ) на сайте разработчиков Mozilla, которыйди намически делает фоновые пиксели зеленого цвета в видеокадре прозрачными, в итоге, элемент img, расположенный под видео, становится видимым сквозь видео, выступая в роли фона. Тот же подход можно использовать для наложения двух видео, в итоге, то видео, которое будет расположено ниже, станет фоном вместо статического изображения. Опять же, помните о производительности маломощных устройств; вы можете решить предоставить параметр, посредством которого пользователь сможет отключить подобные дополнительные эффекты.

    Проигрывание видео и отложенная загрузка

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

    <video src="media/ModelRocket1.mp4" controls loop autoplay></video> 

    Как обычно, мы не будем повторять то, что можно найти среди спецификаций W3C по тегам . Спецификации позволяют узнать о свойствах, методах и событиях этих элементов. Обратите особое внимание на сводные данные по событиям в разделе 4.8.10.15 (http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#event-definitions), и то, что большинство свойств и методов и для того и для другого можно найти в разделе о медиа-элементах, 4.8.10 (http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#media-elements). Обратите внимание на элемент ), больше мы не будем на нем здесь останавливаться.

    Так же полезно понимать, что video и audio тесно связаны, так как они являются частью оной и той же спецификации. На самом деле, если вы просто хотите проиграть звуковую дорожку видеоклипа, вы можете использовать объект Audio в JavaScript:

     //Проигрывание лишь звуковой дорожки видеоклипа	
    var movieAudio = new Audio("http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4");
    
    movieAudio.load();	
    movieAudio.play();	
    

    Для любого видео-элемента вы можете задать ширину и высоту для управления размером области воспроизведений (вплоть до 100% для полноэкранного воспроизведения). Это важно, когда ваше приложение переключается между режимами просмотра и вы, вероятно, имеете CSS-стили видеоэлемента в различных медиа-запросах. Кроме того, если у вас есть элемент управления для полноэкранного воспроизведения, просто сделайте размеры видео такими же, как размер окна просмота (и после вызова ), если приложение находится в прикрепленном режиме). В дополнение, когда вы создаете видеоэлемент с атрибутом controls, у него автоматически появится элемент управления для перевода в полноэкранный режим, в правом углу, который делает именно то, что нужно для приложений Магазина Windows:

    Коротко говоря, вам не нужно делать чего-то особенного для того, чтобы это работало. Когда видео отображается в полноэкранном режиме, похожая кнопка (или клавиша Esc) позволяет вернуться к обычному режиму просмотра приложения.

    Примечание. Если вам интересно, элементы audio и video не предоставляют каких-либо псевдо-селекторов CSS для стилизации панели инструментов. Как сказала дошкольная учительница моего сына (в отношении раздачи фруктового мороженного, но такой подход работает и здесь), "Вы получаете то, что получаете, вы не столкнетесь с истерикой и вы счастливы". Если вы хотите сделать что-то особенное с этими элементами управления, вам нужно выключить элементы по умолчанию и предоставить собственные элементы управления, которые будут соответствующим образом вызывать методы элемента.

    Реализуя собственные элементы управления, убедитесь в том, что установили тайм-аут для их скрытия (либо скрывайте их, либо изменяйте их z-index), когда они не используются. Это особенно важно, если у вас есть кнопка для перевода видео в полноэкранный режим, как та, что имеется во встроенном наборе элементов, с помощью которой вы изменяете размер элемента в соответствии с разрешением экрана. Когда вы выполняете это, Windows автоматически обнаруживает, что видео выводится в полноэкранном режиме и выполняет некоторую оптимизацию производительности, но это не делается, если какие-то еще элементы находятся поверх видео. Хорошая идея – отключать любую выполняемую анимацию и отключать ненужные фоновые процессы, наподобие рабочих веб-процессов.

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

    mediaControl = Windows.Media.MediaControl;	
    mediaControl.addEventListener("soundlevelchanged", soundLevelChanged, false);
    mediaControl.addEventListener("playpausetogglepressed", playpause, false);
    mediaControl.addEventListener("playpressed", play, false);	
    mediaControl.addEventListener("stoppressed", stop, false);	
    mediaControl.addEventListener("pausepressed", pause, false);
     

    Я так же упоминал, что вы можете отложить загрузку видео до того момента, как оно понадобится, и вместо него показать изображение для предварительного просмотра. Это можно реализовать с помощью атрибута poster, значением которого является изображение, которое нужно использовать:

    <video id="video1" poster="media/rocket.png" width="640" height="480"></video>
    
    var video1 = document.getElementById("video1");	
    var clickListener = video1.addEventListener("click", function () {	
    video1.src = "http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4";
    
    video1.load();	
    
    // Удалим прослушиватель для предотвращения пересечения с элементами управления видео
     video1.removeEventListener("click", clickListener);
    
    video1.addEventListener("click", function () {
    video1.controls = true;	
    video1.play();	
    });	
    });	
     

    В данном случае я не использую preload="true" и не задаю src, в итоге ничего не загружается до прикосновения к видео. Когда происходит прикосновение, прослушиватель удаляется, включаются собственные элементы управления видео и начинается воспроизведение. Это, конечно, обходной метод, чаще вы будете исопользовать preload="true" controls src="..." непосредственно в видеоэлементе, в то время, как атрибут poster будет обрабатывать изображения предварительного просмотра.

    Отключение скринсейверов и экрана блокировки при воспроизведении

    При воспроизведении видео, особенно – полноэкранном, важно отключить любые автоматические тайм-ауты, которые могут очистить экран или заблокировать устройство. Это можно выполнить с помощью объекта ). Прежде чем начинать воспроизведение, создайте экземпляр этого объекта и вызовите его метод requestActive.

    var displayRequest = new Windows.System.Display.DisplayRequest();
    displayRequest.requestActive();
     

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

    Расширения API видеоэлемента

    Помимо стандартов HTML5 для элементов video, в Windows 8 к нему добавлены некоторые доополнительные свойства и методы, как показано в следующей табилце и описано на странице "Видеоэлемент" (http://msdn.microsoft.com/library/windows/apps/hh465962.aspx). Кроме того, взгляните на пример "Воспроизведение мультимедиа в HTML" (http://code.msdn.microsoft.com/windowsapps/Media-Playback-Sample-3bdbe7c9), где вы можете найти примеры их использования.

    Свойства Описание
    msHorizontalMirror Логическое значение, которое задает горизонтальное отражение воспроизведения. Это особенно полезно, когда источником видеоэлемента являются данные с камеры, что позволяет пользователю видеть изображение в верной ориентации. Посмотрите примечания к свойству enclosureLocation в разделе "Выбор устройства захвата мультимедиа" ниже.
    msZoom Логическое значение, указывающее на то, разрешено ли видеоэлементу вписываться в пространство дисплея обрезая верхние/нижние или левые/правые части (если имеет значение ).
    msIsLayoutOptimalForPlayback (onMSVideoOptimalLayoutChanged) Логическое значение, которое указывает имеет ли видео наилучшую производительность воспроизведения на основе его макета. Когда это свойство меняется, вызывается событие ) и "Производительность аудио и видео" (http://msdn.microsoft.com/library/windows/apps/hh848311.aspx).
    msIsStereo3D Логическое значение, которое показывает, является ли источник видео трехмерным (на основе метаданных видеофайла). Поддерживает ли подобную функцию система, можно определить посредством ). Приложения так же могут прослушивать событие WinRT Windows.Graphics.Display.DisplayProperties.stereoEnabledChanged (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayproperties.stereoenabledchanged.aspx) для того, чтобы узнать об изменениях возможностей. Для того, чтобы узнать подробностей, касающихся других особенносте стереоскопического 3D-режима, обратитесь к материалу "Включение воспроизведения видео в стереорежиме" (http://msdn.microsoft.com/library/windows/apps/hh452749.aspx), и к Сценарию 5 примера "Воспроизведение мультимедиа в HTML"
    msStereo3DRenderMode Может принимать значение mono (по умолчанию) или stereo, таким образом приложения могут управлять воспроизведением (смотрите подробности выше)
    msStereo3DPackingMode Может иметь значение none (2D-режим по умолчанию), topbottom, или sidebyside; эта настройка доступна приложениям, когда метаданные видео не отражают ориентацию, которую нужно использовать (смотрите выше).
    msRealtime Активирует уменьшение первоначальной задержки воспроизведения настолько, насколько это возможно. Это важно для приложений двусторонней связи, например, так же для игровых чатов, но пользоваться этим следует осмотрительно. Для того, чтобы узнать подробности, обратитесь к материалу "Активация воспроизведения с низкой задержкой" (http://msdn.microsoft.com/library/windows/apps/hh452742.aspx) и к примеру "Связь в реальном времени" (http://code.msdn.microsoft.com/Simple-Communication-Sample-eac73290).Активирует уменьшение первоначальной задержки воспроизведения настолько, насколько это возможно. Это важно для приложений двусторонней связи, например, так же для игровых чатов, но пользоваться этим следует осмотрительно. Для того, чтобы узнать подробности, обратитесь к материалу "Активация воспроизведения с низкой задержкой" (http://msdn.microsoft.com/library/windows/apps/hh452742.aspx) и к примеру "Связь в реальном времени" (http://code.msdn.microsoft.com/Simple-Communication-Sample-eac73290).
    msPlayToDisabled, msPlayToPrimary, msPlayToSource Свойства, связанные с функцией Windows по воспроизведению на целевых объектах (Windows PlayTo). Смотрите раздел "Воспроизведение на целевых объектах" в конце этой лекции. Обратите внимание на то, что это доступно так же для элементов img и audio.
    msAudioTracks Массив описаний аудиозаписей для поддержки дополнительных языков или других записей (то есть – комментариев). Установите ) и к сценарию 2 примера "Воспроизведение мультимедиа в HTML".
    msAudioCategory Идентифицирует вид аудио, проигрываемого в видеозаписи. Смотрите раздел "Управление воспроизведением и фоновое аудио" ниже для того, чтобы узнать подробности. Обратите внимание на то, что установка этого свойства в значение "Communications" так же установит тип устройства в значение "Communications" и переключит msRealtime в значение true.
    msAudioDeviceType Задает выходное устройство, на которое будет отправлено аудио, смотрите "Расширения API аудиоэлемента"."
    Методы Описание
    msFrameStep (onMSVideoFrameStepCompleted) Перемещает видео на одинк кадр вперед или назад. Событие onMSVideoFrameStepCompleted вызывается, когда перемещение завершено.
    msInsertVideoEffect msInsertAudioEffect msClearEffects Добавляет или удаляет видеоэффекты при воспроизведении (смотрите ниже). Все это доступно для видео; msInsertVideoEffect не доступно для аудиоэлементов.
    msSetMediaProtectionManager Используется для DRM и с видео, и с аудио, смотрите раздел "Потоковая передача данных с сервера и DRM" ближе к концу этой лекции.
    msSetVideoRectangle Задает размер внутренней прямоугольной области в видео.
    onMSVideoFrameStepCompleted (event) Происходит при изменении формата видео

    Атрибут source и пользовательские кодеки

    Элементы видео (и аудио) могут использовать атрибут HTML5 ), это не большая проблема для приложений Магазина Windows. Однакое, использование source все еще полезно, так как этот атрибут позволяет идентифицировать конкретный кодек для источника медиаданных:

    <video controls loop autoplay>
    <source src="video1.vp8" type="video/webm" />
    </video>
     

    Это важно, когда вы хотите предоставить пользовательский кодек для приложения посредством Windows.Media.MediaExtensionManager, что описано в разделе "Пользовательские кодеры/декодеры и обработчики схем" ниже в этой лекции, так как кодек идентифицирует расширение для загрузки и применения при декодировании. Я показал здесь в качестве примера WebM, так как он не доступен напрямую приложениям для Магазина Windows (хотя присутствует в Internen Explorer). Когда исполняется хост-процесс, приложение для Магазина Windows, содержащее вышеописанный элемемент video, будет выполнять поиск подходящего декодера для заданного параметра type.

    Применение видеоэффектов

    Вышеприведенная таблица показывает, что у видеоэлемента есть методы msInsertVideoEffect и msInsertAudioEffect. WinRT предоставляет встроенный эффект стабилизации видео, который легко применить к элементу. Это показано в Сценарии 3 примера "Мультимедийные расширения" (), где одно и то же видео проигрывается с использованием эффекта и без него, у стабилизированного видео отключен звук:

    vidStab.msClearEffects(); 
    vidStab.muted = true; 
    vidStab.msInsertVideoEffect(Windows.Media.VideoEffects.videoStabilization, true, null);
     

    Пользовательские эффекты, как показано в Сценарии 4 примера, применяются в виде отдельных динамически связываемых библиотек (DLL), обычно написанных на C++ для лучшей производительности, и включенных в пакет приложения, так как приложения для Магазина Windows могут устанавливать DLL только для собственного использования, а не для общесистемного доступа. В примере вы найдете проекты DLL для перевода изображения в оттенки серого, инверсии и применения геометрических эффектов, где у последних есть три параметра – для эффекта "рыбьего глаза" (fisheye), сжатия (pinch) и деформации (warp). В файле js/customEffect.js вы можете видеть, как применяются эти эфекты, в первом параметре msInsertVideoEffect, который является строкой и идентифицирует эффект, экспортируемый DLL (смотрите, например, файл InvertTransform.idl в проекте InvertTransform):

    vid.msInsertVideoEffect("GrayscaleTransform.GrayscaleEffect", true, null);
    
    vid.msInsertVideoEffect("InvertTransform.InvertEffect", true, null);
     

    Второй параметр msInsertVideoEffect, кстати, показывает, нужно ли применять эффект, обычно он имеет значение true. Третий параметр называется конфигурация (config), он содержит дополнительные сведения, которые передаются в эффект. В случае с геометрическими эффектами в примере, этот параметр задает конкретный вариант эффекта:

    var effect = new Windows.Foundation.Collections.PropertySet();	
    effect["effect"] = effectName;	
    vid.msClearEffects();	
    vid.msInsertVideoEffect("PolarTransform.PolarEffect", true, effect);
     

    Здесь effectName может принимать значения "Fisheye", "Pinch", или "Warp".

    Аудиоэффекты, не показанные в примере, применяются так же, с помощью msInsertAudioEffect (с теми же параметрами). Обратите внимание на то, что каждый элемент может иметь не более двух эффектов в потоке. Элемент video может иметь два видеоэффекта и два аудиоэффекта, элемент audio может иметь два аудиоэффекта. Если вы попытаетесь добавить больше, метод выдаст исключение. Поэтому полезно вызывать msClearEffects перед добавлением эффектов.

    Подробности об эффектах и других расширениях мультимедиа вы можете найти в материале "Применение расширений мультимедиа" (http://msdn.microsoft.com/library/windows/apps/hh700365.aspx).

    Обзор мультимедиа-серверов

    Во многих домашних хозяйствах, и в моем тоже, имеется один или большее количество мультимедиа-серверов, доступных в локальной сети, с которых приложения могут воспроизводить мультимедийные данные. Добраться до этих серверов можно с помощью еще одного свойства ). Как и в слудчае с другими известными папками, это просто объект StorageFolder, посредством которого можно перечислять дополнительные папки и файлы или применять запросы к ним. В данном случае, если вы вызываете его метод getFoldersAsync, вы получаете список доступных серверов, каждый из которых представлен собственным объектом StorageFolder. Здесь вы можете использовать файловые запросы, как было описанов в лекции 2, для поиска мультимедийных да нных интересующих вас типов, или использовать критерии поиска, заданные пользователем. Вот пример, посвященный этому: "Клиент мультимедиа-сервера" (http://code.msdn.microsoft.com/windowsapps/Media-Server-sample-fffbe490).

    Воспроизведение и микширование звука

    Как и в случае с видеоданными, элемент audio предоставляет собственные возможности по воспроизведению, в том числе – элементы управления, циклическое воспроизведение и автовоспроизведение:

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

    Опять же, как описано выше, одни и те же спецификации W3C применимы и к элементу video, и к элементу audio. Уже известный код для проигрывания лишь звуковой дорожки видеофайла, мы можем использовать для проигрывания аудиофайла:

    var sound = new Audio("media/SpringyBoing.mp3");
    sound1.msAudioCategory = "SoundEffect";	
    sound1.load(); //Для предварительной загрузки данных	
    sound1.play(); //В любое время позже	
     

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

    Как и в случае с видео, для приложения, выполняющего воспроизведение звука, важно соответствующим образом реагировать на события, исходящие из объекта ), в особенности на события playpressed, pausepressed, stoppressed, и playpausetogglepressed. Это позволяет пользователю управлять воспроизведением с помощью аппаратных кнопок, которые можно использовать при воспроизведении музыки, например. Однако, вы можете не применять обработку этих событий, например, при воспроизведении игровых звуков.

    Говоря о воспроизведении звука, интересно рассмотреть вопрос о смешивании нескольких звуков, что обычно нужно в играх. Важно понимать, что каждый элемент И, конечно, я играю на гитаре и пою главную партию в этой живой записи, вместе с моим другом Тедом Катлером. Песня "Who is Sylvia?" написана другим моим другом, Дж. Дональдом Уолтерсом, на стихи Шекспира.

    var sound1 = new Audio("media/SpringyBoing.mp3");
    sound1.load(); //Для предварительной загрузки данных
    
    //Фоновая музыка	
    var sound2 = new Audio();	
    sound2.msAudioCategory = "ForegroundOnlyMedia"; //Установим перед установкой src	
    sound2.src = "http://www.kraigbrockschmidt.com/mp3/WhoIsSylvia_PortlandOR_5-06.mp3";
    
    sound2.loop = true;	
    sound2.volume = 0.5; //50%;	
    sound2.play();	
    
    document.getElementById("btnSound").addEventListener("click", function () {
    //Сбрасываем позицию, если уже воспроизводим	
    sound1.currentTime = 0;	
    sound1.play();	
    });	
     

    Загрузив звук, воспроизводимый при касании, мы знаем, что можем воспроизвести его в любое время. При запуске воспроизведения, полезно сбросить currentTime в значение 0, таким образом, звук всегда будет воспроизводиться сначала.

    Вопросы о микшировании, особенно в играх, касаются управления различными звуками без знания наперед времени, когда они будут смешиваться. Вам может быть нужно, например, наложить друг на друга воспроизведение одного и того же звука, с различным временем начала, но объявлять три аудиоэлемента с одним и тем же источником непрактично. Представленная техника касается использования "ротации каналов" ("rotating channels"), как описано здесь: http://ajaxian.com/archives/html5-audio-tutorial-rotating-channels. В итоге получается следующее:

  • Объявляем элементы audio для каждого звука (с установкой preload="auto").
  • Создаем пул (массив) объектов audio для необходимого количества каналов
  • Для воспроизведения звука
  • Получаем доступный объект Audio из пула.
  • Устанавливаем его атрибут src в соответствии с одним из соответствующих элементов audio с предварительно загруженными данными.
  • Вызываем метод play этого объекта из пула.
  • Как обнаружили звукорежиссеры фильмов, нет особенного смысла проигрывать одновременно слишком много звуков, так как звучание становится слишком "грязным". В итоге, вам не понадобится больше пары десятков каналов.

    Подсказка. Нужны звуки для приложения? Загляните на http://www.freesound.org/.

    Расширения API аудиоэлемента

    Как и в случае с элементом video, и для элемента audio доступны некоторы расширения, в частности те, что можно использовать для управления эффектами (msInsertAudioEffect), DRM (msSetMediaProtectionManager), для воспроизведения на целевых объектах (msPlayToSource, и так далее.), msRealtime, и msAudioTracks, как перечислено раньше в разделе о расшираниях API для видеоэлемента. На самом деле, каждое расширение API для аудио существует и для видео, но два из них имеют особую важность для элементов audio: msAudioDeviceType позволяет приложению определить, на какое выходное устройство осуществляется отправка звука: "Console" (по умолчанию) и "Communications". Это способ, благодаря которому приложение знает, что оно участвует в сеансе связи (наподобие чата), что не связано с воспроизведением мультимедийных аудиоклипов.

    msAudioCategory идентифицирует тип проигрываемой аудиозаписи (смотрите таблицу в следующем разделе). Это очень важно для идентификации того, следует ли продолжать воспроизведение музыки в фоновом режиме (тем самым предотвращая перевод приложения в приостановленный режим), как описано далее. Обратите внимание на то, что следует всегда устанавливать это свойство перед установкой src, и на то, что установка режима "Communications" так же устанавливает тип устройства на "Communications" и приводит к установке msRealtime в true.

    Обратите внимание на то, что несмотря на схожесть значений в этих свойствах, msAudioDeviceType предназначено для выбора выходного устройства, в то время как msAudioCategory идентифицирует тип аудиозаписи, которая воспроизводится через любое устройство. Аудио с коммуникационной категорией, например, может воспроизводиться на консольном устройстве, а мультимедийное аудио – на коммуникационном устройстве. За этими двумя свойствами стоят разные концепции.

    Управление воспроизведением и фоновое аудио

    Для того, чтобы рассмотреть различные виды воспроизведения аудио, обратимся к примеру "Средство управления воспроизведением msAudioCategory" (http://code.msdn.microsoft.com/windowsapps/Playback-Manager-e6526e67). Я не привожу здесь скриншот, так как пример лишь работает с аудио, и там особенно нечего показывать! ВВместо этого позвольте мне изложить особенности поведения различных его сценариев следующей таблице, а так же – некоторые категории, которые не представлены в примере, но могут быть использованы в ваших приложениях. В каждом сценарии вам сначала нужно выбрать аудиофайл с помощью средства выбора файлов:

    Сценарий msAudioCategory Описание
    1 BackgroundCapableMedia Воспроизводит выбранный аудиофайл, и когда приложение видимо, и в фоновом режиме, в том числе тогда, когда пользователь находится на Рабочем столе, на Начальном экране или на экране блокировки. Приложение не приостанавливается, находясь в фоновом режиме, в этом можно убедиться посредством Диспетчера задач. Это обычно исопользуется для воспроизведения локальных списков воспроизведения, локальных или потоковых медиафайлов, музыкальных видео и так далее. Использование этой категории требует объявления в манифесте и наличия обработчиков аппаратных кнопок управления воспроизведением.
    2 Communications Как и в случае BackgroundCapableMedia, воспроизведение звука продолжается и когда приложение находится в фоновом режиме. Используйте это для чатов, VoIP-приложений и так далее.
    3 Other (по умолчанию для элементов audio) Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане, микшируется с фоновым аудио, когда приложение переходит в фоновый режим, воспроизведение приостанавливается.
    4 ForegroundOnlyMedia Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане. Воспроизведение приостанавливается, когда приложение переходит в фоновый режим. Когда воспроизводится аудио из этой категории, фоновое аудио отключается.
    5 Alert Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане, ослабляет фоновое аудио. Используется для оповещений, наподобие звонков, и для системных сообщений.
    n/a GameMedia Используется для окружающей музыки в играх.
    n/a GameEffects Используется для игровых звуковых эффектов, предназначенных для смешивания с воспроизводимыми звуками (все немузыкальные звуки).
    n/a SoundEffects Другие звуковые эффекты (за пределами игр), которые предназначены для смешивания с воспроизводимым звуком, такие, как короткие звонки, писки, стуки, бульканья, которые сопутствуют неким действиям, но не являются оповещениями.

    Когда речь идет об отдельном звуковом потоке, между некоторыми из этих категорий нет особой разницы. Действительно, как показано в таблице, звуки разных категорий по-разному воздействуют на другие звуковые потоки, проигрываемые одновременно с ними. Для этой цели в Windows SDK сделан необычный ход: предоставлен второй пример, идентичный вышеописанному, "Дополнительный пример для средства управления воспроизведением" (http://code.msdn.microsoft.com/windowsapps/Playback-Manager2-55c5b86d). Это позволяет вам запустить данные приложения одновременно (одно – в прикрепленном режиме, другое в заполняющем, или одно, либо оба, в фоновом режиме) и воспроизводить аудио различных категорий, наблюдая их взаимодействие.

    Как комбинируются различные аудиопотоки, рассматривается в документе "Воспроизведение аудио в приложениях для Windows 8" (http://msdn.microsoft.com/library/windows/hardware/hh770517.aspx). Однко, самое важное, это чтобы вы присваивали каждому аудиопотоку наиболее соответствующую ему категорию. Эти категории помогают средству управления воспроизведением правильно микшировать звуковые потоки, основываясь на ожиданиях пользователя. Речь идет и о нескольких потоках в одном приложении, и о потоках аудио, поступающих от разных приложений (с ограничением количества приложений, которые могут одновременно воспроизводить аудио в фоновом режиме). Например, пользователи ожидают, что будильник, важная форма оповещения, временно приглушит другие аудиопотоки. Похожим образом, пользователи ожидают, что аудиопоток от приложения переднего плана имеет преимущество перед потоком той же категории, воспроизводимым в фоновом режиме. Как разработчик, поэтому, избегайте развлечений с категориями. Просто на значайте наиболее подходящие категории вашим аудиопотокам и позвольте средству управления воспроизведением делать свою работу с аудио, которое поступает из всех источников и создает последовательный опыт взаимодействия пользователя и системы в целом.

    Установка категории для любого элемента audio, заключается в простом задании его атрибута msAudioCategory. Каждый сценарий в примере выполняет это одинаково, устанавливая категорию перед установкой атрибута src (здесь показан код из js/backgroundcapablemedia.js):

    audtag = document.createElement('audio'); 
    audtag.setAttribute("msAudioCategory", "BackgroundCapableMedia");
     audtag.setAttribute("src", fileLocation);
     

    Конечно, вы можете сделать то же самое в разметке. Вот примеры:

    <audio id="audio1" src="song.mp3" msAudioCategory="BackgroundCapableMedia"></audio>
    <audio id="audio2" src="voip.mp3" msAudioCategory="Communications"></audio>
    <audio id="audio3" src="lecture.mp3" msAudioCategory="Other"></audio>
     

    Однако, в случае с BackgroundCapableMedia and Communcations недостаточно лишь установить категорию: вам так же нужно задать расширение фоновой задачи в манифесте. Это просто сделать на закладке Объявления (Declarations) редактора манифеста:

    Во-первых, выберите Фоновые задачи (Background tasks) из выпадающего списка Доступные объявления (Available declarations). Затем установите флаг Аудио (Audio) в группе Поддерживаемые типы задач (Supported task types) и укажите начальную страницу (Start page) в разделе параметров приложения (App settings). Начальная страница не особенно важна для фонового аудио (так приложение никогда не будет запущено извне для этой цели), но это нужно для соответствия правилам заполнения манифеста.

    В XML-файле манифеста эти объявления выглядят следующим образом, взгляните на них:

    <Application Id="App" StartPage="default.html">
    <!-- ... -->
    <Extensions>
    <Extension Category="windows.backgroundTasks" StartPage="default.html">
    <BackgroundTasks>
    <Task Type="audio" />
    </BackgroundTasks>
    </Extension>
    </Extensions>
    </Application>
     

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

    Как это сделать, показано в примере о средстве управления воспроизведением. Вот код (часть опущена) из файла js/communication.js:

    mediaControl = Windows.Media.MediaControl;
    
    mediaControl.addEventListener("soundlevelchanged", soundLevelChanged, false);
    mediaControl.addEventListener("playpausetogglepressed", playpause, false);	
    mediaControl.addEventListener("playpressed", play, false);	
    mediaControl.addEventListener("stoppressed", stop, false);	
    mediaControl.addEventListener("pausepressed", pause, false);	
    
    
    // переменная audtag это глобальный аудиоэлемент для страницы
    function playpause() {	
    if (!audtag.paused) {
    audtag.pause();	
    } else {	
    audtag.play();	
    }	
    }	
    function play() {
    audtag.play();
    }
    
    function stop() {
    // Здесь ничего не делается
    }
    
    function pause() {
    audtag.pause();
    }
    function soundLevelChanged() {	
    //Перехватываем уведомление SoundLevel и определяем его состояние.
    //Если звук выключен, приостанавливаем воспроизведение.	
    var soundLevel = Windows.Media.MediaControl.soundLevel;	
    //Здесь ничего не делается, параметры приведены для показа содержимого перечисления 
    switch (soundLevel) {
    case Windows.Media.SoundLevel.muted:
    break;
    case Windows.Media.SoundLevel.low:
    break;
    case Windows.Media.SoundLevel.full:
    break;
    }
    appMuted();
    }
    function appMuted() {	
    if (audtag) {	
    if (!audtag.paused) {
    audtag.pause();	
    }	
    }	
    }	
     

    С технической точки зрения, обработчик для события soundLevelChanged здесь не требуется, но другие четыре нужны. Подобная минимальная реализация – это часть упражнения к этой лекции AudioPlayback, код которого так же использует флаг MediaControl.isPlaying для настройки кнопки проигрывание / пауза в пользовательском интерфейсе проигрывателя аудио (смотрите в следующем разделе).

    Вот некоторые дополнительные замечания, касающиеся фонового аудио:

  • Причина, по которой мы различаем события paypressed, pausepressed и playpaysepressed заключается в поддержке разнообразного аппаратного обеспечения, при этом некоторые устройства имеют раздельные кнопки запуска воспроизведения и постановки на паузу, а у некоторых предусмотрена лишь одна кнопка и для того, и для другого.
  • Если воспроизведение аудио приостановлено, приложение, воспроизводящее фоновое аудио, будет приостановлено, как и прочие, но если пользователь нажмет кнопку воспроизведения, приложение возобновит работу и продолжит проигрывание аудио.
  • Использование функции фонового воспроизведения аудио тщательно оценивается при отправке приложения в Магазин Windows. Если вы попытаетесь проигрывать беззвучную запись для того, чтобы предотвратить приостановку приложения, приложение не пройдет сертификацию.
  • Приложения фонового воспроизведения аудио должны осторожно использовать сетевое соединение для приема потоковых данных для поддержки состояния низкого потребления энергии, которое называется режим ожидания с подключением (connected standby). Подробности вы можете узнать в материале "Создание приложений фонового воспроизведения мультимедиа, экономящих энергию" (http://msdn.microsoft.com/library/windows/desktop/jj247568.aspx).
  • Посмотрим теперь на еще одну важную причину, по которой мы должны реализовывать события элементов управления мультимедиа: пользовательский интерфейс, который Windows отображает в ответ на нажатия аппаратных кнопок.

    Пользовательский интерфейс управления воспроизведением

    Как было упомянуто в предыдущем разделе, приложениям, которые воспроизводят фоновое аудио, нужно предоставлять обработчики событий объекта MediaControl. Благодаря этому пользовали могут управлять воспроизведением с помощью аппаратных кнопок (они встроены во многие устройства, в том числе – клавиатуры, пульты дистанционного управления) без необходимости переключаться на приложение. Это особенно важно, так как фоновое аудио продолжает воспроиизводиться не только тогда, когда пользователь переключается к другому приложению, но и тогда, когда пенеходит на Начальный экран, и на рабочий стол, или блокирует устройство.

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

    На изображениях вы можете видеть имя приложения, по умолчанию отображаемое в интерфейсе, взятое из свойства Отображаемое имя (Display Name), из манифеста. Хотя это и применимо, в идеале аудиоприложению следует передавать подробные метаданные записи в ), который показывает, как получать сведения об альбоме для аудиозаписи, мы вернемся к этому позже.

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

    Вы можете заметить в вышеприведенных изображенийх, что кнопки перехода на следующую и предыдущую запись заблокированы. Это потому, что приложение не имеет прослушивателей для событий nexttrackpressed и previoustrackpressed объекта MediaControl. Мы увидим, как пользоваться ими, в следующем разделе. Есть, так же, и другие события, такие, как channeldownpressed, channeluppressed, fastforwardpressed, rewindpressed, recordpressed, и stoppressed, хотя они и не представлены в интерфейсе.

    Последовательное воспроизведение аудиозаписей

    Приложения, которые воспроизводят аудиозаписи (такие, как музыку, аудиокниги или записи лекций) часто имеют некоторый список записей для последовательного воспроизведения, в особенности, когда приложение исполняется в фоновом режиме. В данном случае важно быстро начинать воспроизведение следующей записи, так как в противном случае Windows приостановит приложение через 10 секунд после завершения воспроизведения текущей записи. Для этой цели прослушивают событие ended элемента audio и устанавливают audio.src на следующую запись. В данном случае хорошая оптимизация заключается в использовании второго объекта Audio и установка его атрибута src после того, как первая запись начнет воспроизводиться. Таким образом, вторая запись будет предварительно загружена и готова к немедленому воспроизведению, таким образом, устраняя потенциальные задержки между записями при воспроизведении. Это реализовано в упражнении к этой лекции AudioPlayback, где я разделил одну песню на четыре сегмента для непрерывного воспроизведения. Я так же покажу здесь, как обрабатывать событии кнопок "Предыдущая запись" и "Следующая запись", вместе с установкой номера сегмента в качестве названия записи:

    var mediaControl = Windows.Media.MediaControl;	
    var playlist = ["media/segment1.mp3", "media/segment2.mp3", "media/segment3.mp3",
    "media/segment4.mp3"];	
    var curSong = 0;	
    var audio1 = null;	
    var preload = null;	
    
    document.getElementById("btnSegments").addEventListener("click", playSegments);
    audio1 = document.getElementById("audioSegments");
    preload = document.createElement("audio");
    
    function playSegments() {	
    //Всегда сбрасывайте прослушиватели событий объектов 
    WinRT для предотвращения дублирования и утечек памяти
    mediaControl.removeEventListener("nexttrackpressed", nextHandler);	
    mediaControl.removeEventListener("previoustrackpressed", prevHandler);	
    	
    curSong = 0;	
    
    //Приостановим другую музыку 
    document.getElementById("musicPlayback").pause();
    
    //Set up media control listeners setMediaControl(audio1);
    
    //Покажем элемент (изначально скрытый) и начнем воспроизведение
    audio1.style.display = "";
    audio1.volume = 0.5; //50%;
    playCurrent();
    
    //Предварительная загрузка следующая запись и готовность к переключению 
    var preload = document.createElement("audio"); preload.setAttribute("preload", "auto");
    preload.src = playlist[1];
    
    //Переключаемся на следующую запись, как только очередная окончится или 
    будет нажат кнопка "Следующая запись"
    audio1.addEventListener("ended", nextHandler);	
    mediaControl.addEventListener("nexttrackpressed", nextHandler);	
    }	
    }	
    function nextHandler () {
    curSong++;
    
    //Активируем кнопку "Предыдущая запись", если у нас есть
     хотя бы одна предыдущая запись	
    if (curSong > 0) {	
    mediaControl.addEventListener("previoustrackpressed", prevHandler);
    }	
    
    if (curSong < playlist.length) {
    //playlist[curSong] уже должен быть загружен
    playCurrent();
    
    //Установка следующей заранее загруженной композиции
    var nextTrack = curSong + 1;
    
    if (nextTrack < playlist.length) {
    preload.src = playlist[nextTrack];
    } else {
    preload.src = null;
    mediaControl.removeEventListener("nexttrackpressed", nextHandler);
    }
    }
    }
    
    function prevHandler() {	
    //Если уже проигрываем последнюю запись, 
    снова добавим обработчик кнопки "Следующая запись"
    if (curSong == playlist.length - 1) {	
    mediaControl.addEventListener("nexttrackpressed", nextHandler);	
    }	
    
    curSong--;
    
    if (curSong == 0) {
    mediaControl.removeEventListener("previoustrackpressed", prevHandler);
    }
    
    playCurrent();
    preload.src = playlist[curSong + 1]; //Это должно работать всегда
    }
    
    function playCurrent() {	
    audio1.src = playlist[curSong];	
    audio1.play();	
    mediaControl.trackName = "Segment " + (curSong + 1);
    }	
     

    При последовательном проигрывании записей, как здесь, из приложения, написанного на JavaScript и HTML, вы можете отметить небольшие паузы между записями, особенно, если первая запись напрямую переходит во вторую. Это существующие ограничения платформы, где существуют уровни между HTML-элементом audio и низкоуровневым API XAudio2, которое, в конечном счете, выполняет реальную работу. В какой-то мере вы можете смягчить этот эффект, например, вы можете организовать плавный переход одной записи в другую, или наложить третью запись на конец первой и начало второй. Так же вы можете использовать отрицательное значение смещения по времени для начала воспроизведения второй записи немного раньше, чем будет окончена первая. Но если вам нужен по-настоящему бесшовный переход между записями, вам нужно обойти элемент audio и использовать API XAudio2 из WinRT-компонента для непосредственного воспроизведения музыки. О том, как это сделать, идет речь в сообщении блога для разработчиков приложений для Windows 8: "Создание собственных компонентов среды выполнения Windows для разработки эффективных приложений" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/08/13/windows-metro.aspx).

    Страницы:

    Файлы к данной лекции Вы можете скачать здесь.

    Говорить, что средства аудиовизуальной информации важны для приложений – и для культуры в целом – это грубое преуменьшение. С тех пор, как люди, подобные Эдисону, сделали возможным записывать произведения для того, чтобы позже ими можно было насладиться, влечение человечества к мультимедийным данным – к изображениям, аудиозаписям, видеоклипам – возможно превысило тягу к автомобилям, электричеству и нездоровой пище. В ранние дни Интернета передача изображений легко занимала большую часть сетевого трафика. Сегодня, потоковое видео даже из одного отдельно взятого ресурса вроде Netflix поддерживает усилия по увеличению возможностей инфрастрктуры широкополосных сетей! (У меня дома это так и есть, с любимыми фильмами моего маленького сына вроде "Curious George", "Bob the Builder", "Dinosaur Train" и другими.)

    Включение в себя, в той или иной форме, мультимедийной информации, это одна из основных забот большинства приложений для Магазина Windows. Простые, вероятно используют лишь несколько изображений для придания приложению фирменного стиля и отображения привлекательного пользовательского интерфейса, как мы уже видели много раз. Многие другие, особенно игры, конечно, используют и графику, и видео и аудио. В контексте этого курса все это поразумевает использование таких элементов HTML5, как img, svg (Scalable Vector Graphics – Масштабируемая векторная графика), canvas, audio и video.

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

  • Организация и правка медиафайлов, в том числе тех, что хранятся в библиотеках изображений, музыки и видео.
  • Конверсия (преобразование) медиафайлов, возможно, с применением различных фильтров и пользовательских кодеков.
  • Организация и правка плей-листов.
  • Захват аудио и видео с доступных устройств.
  • Потоковая передача данных с сервера на устройства, или с устройства на целевые объекты воспроизведений (PlayTo target), возможно, с применением DRM.
  • Эти возможности, для реализации которых существует множество API WinRT, вместе с мультимедиа-элементами HTML5 и их особыми возможностями в среде Windows 8, будут рассмотрены в этой лекции.

    Примечание. Обратите внимание на полный список аудио и видео-форматов, которые поддерживаются WinRT-приложениями: "Поддерживаемые форматы звука и видео" (http://msdn.microsoft.com/library/windows/apps/hh986969.aspx).

    Врезка: Трюки по повышению производительности для создания более быстрых приложений

    Некоторые из рекомендаций, данных в этой лекции, взяты из отличного выступления Джейсона Вебера, который занимается вопросами производительности Internet Explorer. Это выступление называется "50 трюков по повышению производительности, которые позволяют сделать ваше приложение для Windows 8, использующее HTML5, быстрее" (http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-386T). В то время, как некоторые из этих трюков имеют смысл для веб-приложений, которые исполняются в браузере, многие из них полностью применимы к приложениям для Магазина Windows, написанных на JavaScript, так как они исполняются на основе той же инфраструктуры, что имеется в Internet Explorer.

    Создание мультимедиа-элементов

    Конечно, самый простой способ включить мультимедийные данные в приложение – это то, что мы делаем уже многие годы: просто использовать подходящий HTML-элемент в разметке, и вуаля! – все сделано. С элементами img , audio, и video, на самом деле, вы без проблем можете исползовать содержимое из почти любого источника. То есть, атрибутам src этих элементов может быть назначены URI, которые указывают на содержимое в пакете приложения (с использованием относительных путей, URI ms-appx:/// , или путей, основанных на Windows.ApplicationModel.Package.current.installedLocation, которые затем передают в URL.createObjectURL), на файлы в папках данных приложения (с использованием URI ms-appdata:/// , или путей, основанных на Windows.Storage.ApplicationData.current с применением URL.createObjectURL), на удаленные файлы с применением http:// и других URI. В случае с элементом img сюда можно еще добавить использование в качестве источников SVG-файлов.

    Существуют три способа создания мультимедиа-элемента на странице или на элементе управления страницы:

    Во-первых, можно включить элемент напрямую в декларативный HTML-код. Часто полезно использовать атрибут preload="auto" для удаленного аудио или видео для увеличения скорости реакции элементов управления и других элементов пользовательского интерфейса, которые зависят от этих элеменов. (Это важно делать и для локальных медиафайлов, хотя они и так являются локальными!). Часто мультимедийные элементы размещают ближе к верхней части HTML-файла, в порядке приоритета, таким образом, их загрузка может начаться уже в то время, когда остальные части документа еще обрабатываются.

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

    Воспроизведение для элементов, заданных декларативно, может быть начато автоматически, благодаря атрибуту autoplay, посредством встроенного пользовательского интерфейса, если элемент имеет атрибут controls, или с помощью вызова из JavaScript команды <element>.play().

    Второй метод заключается в создании HTML-элемента в JavaScript посредством document.createElement и в добавлении его в DOM с помощью команды <parent>.appendChild и похожих методов. Вот пример использования мультимедиа-файлов, который находится в дополнительных материалах к этой лекции, хотя вам нужно поместить этот код в новый собственный проект:

     //Создаем элемент и добавляем его в DOM, что приведет к изменению макета
    var picture = document.createElement("img");	
    picture.src = "media/wildflowers.jpg";	
    picture.width = 300;	
    picture.height = 450;	
    document.getElementById("divShow").appendChild(picture);	
    
    var movie = document.createElement("video");
    movie.src = "media/ModelRocket1.mp4"; 
    movie.autoplay = false;
    movie.controls = true;
    document.getElementById("divShow").appendChild(movie);
    
    var sound = document.createElement("audio");	
    sound.src = "media/SpringyBoing.mp3";	
    sound.autoplay = true; //Запускаем проигрывание как только элемент будет добавлен в DOM	
    sound.controls = true; //Если установлено false, аудио проигрывается, но не влияет на макет
    document.getElementById("divShow").appendChild(sound);
    

    Если элементы для вывода изображений или видео не скрыты с помощью стилей, а так же, если речь идет об элементах с установленным атрибутом controls, то их добавление вызывает повторную отрисовку макета документа. Аудио-элемент без данного атрибута не приводит к повторному выводу макета. Как и в декларативном HTML, установка аutoplay в значение true приведет к запуску воспроизведения видео или аудио сразу после того, как элемент будет добавлен в DOM.

    И, наконец, для аудио, приложения могут создавать объект Audio в JavaScript для проигрывания звуков или музыки без какого-либо воздействия на пользовательский интерфейс. Больше об этом будет позже. В JavaScript так же есть класс Image, класс Audio может быть использован для загрузки видео:

    //Создаем объекты (с предварительной загрузки), затем нужным образом задаем источники других DOM-объектов	
    var picture = new Image(300, 450);	
    picture.src = "http://www.kraigbrockschmidt.com/downloads/media/wildflowers.jpg";
    
    document.getElementById("image1").src = picture.src;	
    
    //Объект Audio можно использовать для предварительной загрузки 
    (но не воспроизведения) видео
    var movie = new Audio("http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4");
    document.getElementById("video1").src = movie.src;
    
    var sound = new Audio("http://www.kraigbrockschmidt.com/downloads/media/SpringyBoing.mp3");
    document.getElementById("audio1").src = sound.src;
     

    Создание объектов Image или Audio из кода не приводит к созданию элементов в DOM, что может быть полезным. Объект Image, например, многие годы используется для предварительной загрузки массивов исходных изображений для использования в задачах наподобие вращения изображений или при реализации всплывающих меню. Предварительная загрузка в данном случае означает лишь то, что изображения были загружены и кэшированы. Таким образом, присваивание того же самого URI атрибуту SRC элемента, который уже находится в DOM, как показано выше, приведет к немедленному появлению изображения. То же самое справедливо для предварительно загруженного видео и аудио, но, опять же, это, в первую очередь, полезно для использования с удаленными источниками, в то время, как файлы из локальной файловой системы загружаются сравнительно быстро и без дополнительных усилий с нашей стороны. Тем не менее, если у вас есть большие локальные изображения, и вы хотите быстро показать их, когда они понадобятся, предварительная загрузка их в па мять – это полезная стратегия.

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

    Графические элементы: Img, Svg и Canvas (и немного CSS)

    Знаю, вам, вероятно, не терпится прочесть разделы этой лекции, посвященные аудио и видео, но мы не можем забывать о том, что изображения были основой веб-приложений с самого начала и их важность в реализации опыта взаимодействия пользователя и приложения все еще огромна. Действительно, полезно помнить о том, что видео, концептуально, это лишь последовательный набор статических изображений, быстро сменяющих друг друга! К счастью, HTML5 значительно расширил возможность приложений по включению в себя графических данных путем добавления поддержки формата SVG и элемента canvas к проверенному временем элементу управления img. Кроме того, применение CSS-анимаций и переходов (этому посвящена лекции 7-8) к элементам изображений, которые иначе неподвижны, позволяет сделать их очень динамичными.

    Говоря о CSS, важно отметить, что многие графические эффекты, которые раньше требовали применения соответствующим образом подготовленного статического изображения, могут быть реализованы только с использованием CSS, в частности, с применением CSS3:

  • Границы, фоновые цвета, фоновые изображения.
  • Изображения закладок папок, меню, панели инструментов.
  • Скругленные углы границ, использование нескольких границ и фонов, границы изображений
  • Прозрачность
  • Встраиваемые шрифты
  • Тени объектов
  • Тени текстов
  • Градиенты
  • Коротко говоря, если вы когда-либо использовали элементы ) от Smashing Magazine и к спецификациям CSS3 на http://www.w3.org/. CSS так же предоставляет возможность декларативно обрабатывать некоторые события и визуальные состояния с использованием псевдо-селекторов для и к еще материалу Smashing Magazine по псевдо-классам (http://coding.smashingmagazine.com/2011/03/30/how-to-use-css3-pseudo-classes/).

    Рассмотрим теперь три основные HTML5-элемента для вывода изображений:

  • Элемент img используется для растровых изображений. Формат PNG предпочтителен по сравнению с другими, особенно для текстов и штриховых рисунков, хотя JPEG-файлы фотографий имеют меньший размер. GIF, как правило, считается устаревшим, в тех случаях, когда использование GIF-файлы давало выигрыш за счет маленького размера, теперь можно пользоваться исключительно CSS. Если речь идет о масштабировании, приложения для Магазина Windows должны учитывать плотность пикселей, как мы видели в лекции 6 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", и предоставлять различные файлы изображений ля каждого масштаба, с которым может столкнуться приложение. Это тот случай, когда JPEG-файлы меньшего размера могут уменьшить общий размер пакета приложения в Магазине Windows.
  • Формат SVG лучше всего использовать для плавного масштабирования изображений на мониторах разного размера и разной плотности пикселей. SVG-изображения могут быть описаны внутри HTML-кода, созданы динамически в DOM, ими можно управлять как отдельными файлами и использовать в качестве источника для элемента img (в этом случае все характеристики масштабирования поддерживаются). SVG-файл так же может быть использован как источник для iframe, что дает преимущества в виде доступности дочерних элементов SVG в DOM. Как мы видели в лекции 6 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", сохранение соотношения сторон SVG-изображения часто важно, для чего мы использовали viewBox и атрибуты preserveAspectRatio тега svg.
  • Элемент canvas (холст) предоставляет поверхность для рисования и API для создания изображений с использованием линий, прямоугольников, дуг, текста и так далее. Холст, в итоге, генерирует растровые данные, что означает, что будучи однажды созданным, такое изображение масштабируется как растровое. (Приложение, конечно, обычно перерисовывает холст с масштабированием координат для того, чтобы избежать пикселизации). Холст весьма полезен для выполнения манипуляций с пикселями, даже с отдельными кадрами видео, когда оно проигрывается.
  • Приложения часто используют все три элемента, опираясь на их сильные стороны. Я говорю это, так как, когда элемент canvas впервые стал доступен, разработчики оказались так им очарованы, что, казалось, забыли, как пользоваться img и они игнорируют тот факт, что часто SVG – это наилучший вариант! (И я ведь уже сказал, что CSS сам по себе способен на многое, а?)

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

    Что отличает эти элементы друг от друга, так это то, как в них поступают данные. Элементы img загружают данные из файла-источника, svg-данные заданы в разметке, элементы canvas заполняются посредством программного кода. Но, в конце концов, как показано в Сценарии 1 упражнения "Графика в HTML" для этой лекции, и как отражено на рис. 5.1 все они производят одинаковые результаты: (рис 5.1) Элементы img, canvas и svg показывают одинаковый результат

    Коротко говоря, в том, что может быть выведено с помощью каждого из элемента, нет фундаментальных различий. Тем не менее, у них есть различия, которые становятся очевидными, когда мы начинаем манипулировать этими элементами как и в случае с CSS. Так каждый элемент – это лишь узел в DOM, простой и ясный, и они рассматриваются как и все другие, неграфические элементы: CSS не влияет на внутреннее содержимое элементов, а влияет лишь на то, как они, в итоге, отображаются на странице. Отдельные части SVG, объявленные в разметке, могут, на самом деле, быть отдельно стилизованы до тех пор, пока их можно идентифицировать с помощью CSS-селекторов. В любом случае, подобная стилизация влияет только на внешний вид, таким образом, если применяются новые стили, они применяются к исходному содержимому элемента.

    Справедливо и то, что графические элементы могут перекрывать друг друга и неграфические элементы (как и видео), и подсистема визуализации автоматически обрабатывает прозрачность в соответствии с параметром z-index этих элементов. Каждый графический элемент может иметь чистые, или прозрачные области, которые встроены в форматы изображений наподобие PNG. В элементе canvas, любые области, очищенные с помощью метода clearRect, которые иным образом не затрагивают другие вызовы API, будут прозрачными. Похожим образом, любая область прямоугольного элемента SVG, которая не затронута его отдельными частями, будет прозрачной.

    Сценарий 2 в упражнении "Графика в HTML" позволяет вам включать несколько стилей (с помощью флагов) для тех же элементов, которые показаны ранее. В данном случае я сделал фон элемента canvas прозрачным, таким образом, мы можем видеть то, что распложено за ним. Когда стили применяются, элемент img оказывается повернутым и трансформированным, к canvas применяется масштабирование, и отдельные части svg-элемента стилизуются новыми цветами, как показано на рис. 5.2. (рис 5.2) Стили, примененные к графическим элементам; отдельные элементы SVG могут быть стилизованы, если они доступны посредством DOM

    Стили, заданные в css/scenario2.css, довольно просты:

    .transformImage {
    transform: rotate(30deg) translateX(120px);
    }
    
    .scaleCanvas {
    transform: scale(1.5, 2);
    }
     

    Как и код в js/scenario2.js, который их применяет:

    function toggleStyles() {
    var applyStyles = document.getElementById("check1").checked;
    
    document.getElementById("image1").className = applyStyles ? "transformImage" : "";
    document.getElementById("canvas1").className = applyStyles ? "scaleCanvas" : "";
    
    document.getElementById("r").style.fill = applyStyles ? "purple" : "";	
    document.getElementById("l").style.stroke = applyStyles ? "green" : "";	
    document.getElementById("c").style.fill = applyStyles ? "red" : "";	
    document.getElementById("t").style.fontStyle = applyStyles ? "normal" : "";	
    document.getElementById("t").style.textDecoration = applyStyles ? "underline" : "";
     }	
     

    Другая особенность, которую вы могли заметить при применении стилей, это то, что увеличенный элемент canvas выглядит пикселизованным, как обычно бывает с растровыми изображениями. Это вполне ожидаемое поведение, как показано в следующей таблице о характеристиках масштабирования. Это показано в Сценариях 3 и 4 упражнения "Графика в HTML".

    Элемент Масштабирование Обработка изменений макета для лучшего отображения
    img растеризованное Измените атрибут src для различных масштабов (или просто используйте SVG-файл в качесте источника).
    canvas растеризованное Перерисуйте холст с использованием масштабированных размеров; часто это можно сделать наилучшим образом, вызвав <context>.scale в соответствии с необходимым размером отображения вместо изменения координат, использованных в коде
    svg плавное Нет необходимости. Используйте viewBox и preseveAspectRatio для пропорционального изменения масштаба.

    Дополнительные характеристики графических элементов

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

    Элемент Операции, вызывающие перерисовку Режим Преимущества
    img Изменение атрибута src Изменение стиля из JavaScript Пиксельный

    Быстро выводится и трансформируется

    Отлично подходит для статических элементов и статических/повторяющихся фонов

    Возможна спрайтовая анимация путем изменения атрибута src

    canvas

    Вызов контекстного API

    Изменение стиля из JavaScript

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

    Немедленный: вызовы API приводят к выводу пикселей и не запоминаются

    Качественный динамический контент

    Быстро выводится после перерисовки

    Возможность манипуляции изображением на уровне пикселей

    Отлично подходит для качественного динамического/интерактивного содержимого с частым использованием вычислений.

    svg

    Изменение структуры элемента

    Изменение стиля из JavaScript

    С запоминанием: все фигуры существуют как элементы DOM (если не используется в атрибуте img src)

    Плавное масштабирование

    Точное управление отдельными (запоминаемыми) элементами

    Возможность манипуляции на уровни фигур

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

    Так как SVG создает элементы в DOM, эти элементы могут быть стилизованы индивидуально. Вы можете использовать этот факт вместе с медиа-запросами для скрывать разные части SVG в зависимости от их размера. Для того, чтобы сделать ээто, добавьте различные классы к таким SVG-элементам, затем, в CSS, добавьте или удалите стиль display: none для этих классов в медиа-запросах наподобие @media (min-width:300px) and (max-width:499px) . Вам может понадобиться рассчитать размер SVG по отношению к окну приложения, но это означает, что вы можете эффективно убрать детали из SVG вместо того, чтобы позволять этим частям отрисовываться на слишком малом пространстве, чтобы быть полезными.

    В итоге, причина по которой HTML5 имеет все три элемента, заключается в том, что все три по-настоящему нужны. Все они способны получить преимущества от полного аппаратного ускорения, так же, как это происходит в Internet Explorer, так как приложения, написанные на HTML и JavaScript исполняются на той же подсистеме визуализации, что и браузер.

    Лучший подход к дизайну приложений – по-настоящему исследовать подходящие варианты использования элементов каждого типа. Каждый элемент может иметь прозрачные области, в итоге, вы можете легко достигнуть весьма забавных эффектов. Например, если у вас есть данные, которые выводят временную информацию о видео или другой текст, в надпись, вы можете просто использовать обработчик интервалов (с интервалом, установленным на необходимую детализации, пол секунды, например), получить свойство видео currentTime, получить необходимый текст для данного фрагмента, и вывести текст на пэлементе canvas c прозрачным фоном, который расположен поверх видео. Субтитры и другие сведения о видео можно вывести похожим образом, устраняя необходимость в перекодировании видео.

    Некоторые советы и секреты

    Работа с графическими элементами HTML5 довольно проста, но знание некоторых подробностей может помочь в работе с ними в приложениях для Магазина Windows.

    Элементы Img

  • Используйте атрибут title элемента img для реализации всплывающей подсказки, а не атрибут alt. так же вы можете использовать элемент управления WInJS.UI.Tooltip, как показано в лекции 4 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript".
  • Для создания изображений из потока, расположенного в памяти, воспользуйтесь методом ), результат его работы затем можно передать в URL.createObjectURL для создания подходящего для атрибута src URL. Мы встретимся с этим в данной лекции, и нам это понадобится при работе с контрактом "Общий доступ" в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой". Та же техника работает для аудио и видео-потоков.
  • Загружая изображение из http:// или с другого удаленного источника, вы рискуете столкнуться с отображением в элементе изображения-заполнителя с красным значком "X". Для того, чтобы предотвратить это, перехватите событие img.onerror и предоставьте собственный элемент-заполнитель:
    var myImage = document.getElementById('image');
    myImage.onerror = function () { onImageError(this);}
    function onImageError(source) {	
    source.src = "placeholder.png";
    source.onerror = "";	
    }	
     
  • Элементы SVG

  • Теги <script> не поддерживаются внутри <svg> .
  • Если у вас есть SVG-файл, вы можете загрузить его в элемент img, сославшись на файл в атрибуте src, но это не позволит вам обходить SVG в DOM. Если вам нужно подобное поведение, загрузите SVG в iframe. Содержимое SVG тогда будет расположено внутри свойства contentDocument.documentElement:
    <!-- В HTML-->
    <iframe id="Mysvg" src="myFolder/mySVGFile.svg" />
    
    // В JavaScript
    var svg = document.getElementById("Mysvg").contentDocument.documentElement;
     
  • Файлы в форматах PNG и JPEG обычно обрабатываются быстрее, чем SVG, поэтому, если технической необходимости в использовании SVG нет, или если вы имеете дело со сценарием, требующем высокой производительности, рассмотрите вариант использования масштабированных растровых изображений. Или вы можете динамически создавать масштабированные статические изображения из SVG для того, чтобы использовать их позже для более быстрого рендеринга:
    <!-- В HTML-->
    <img id="svg" src="somesvg.svg" style="display: none;" />
    <canvas id="canvas" style="display: none;" />
    // В JavaScript	
    var c = document.getElementById("canvas").getContext("2d");	
    c.drawImage(document.getElementById("svg"),0,0);	
    var imageURLToUse = document.getElementById("canvas").toDataURL();
    
  • Вот два полезных материала по SVG: http://www.carto.net/papers/svg/samples/ и http://srufaculty.sru.edu/david.dailey/svg/.
  • Элементы Canvas

    Все упомянутые здесь имена фукнций – это методы объекта контекста canvas:

  • Помните, что элемент canvas нуждается в задании атрибутов width и height (в JavaScript – canvas.width и canvas.height), а не стилей. Он не принимает таких единиц измерения, как px, em, % и других.
  • Несмотря на имя, метод closePath не является прямым дополнением метода beginPath. Метод beginPath используется для создания нового контура, который может быть обведен линией, сбрасывая существующий контур. Метод closePath, с другой стороны, просто соединяет две конечных точки текущего контура, как если бы вы исполнили для этих точек команду lineTo. Он не сбрасывает контур и не создает новый. Это часто вызывает у программистов путаницу, и поэтому иногда можно видеть окружности, нарисованные с линией, проведенной к их центру!
  • Вызов stroke необходим для отрисовки контура, до этого вы можете рассматривать его как карандашный набросок чего-либо, который пока не закрашен тушью. Обратите так же внимание на то, что обведение контура означает вызов beginPath.
  • При анимации содержимого canvas, выполнение clearRect для всего элемента и перерисовка каждого кадра обычно легче реализуема, чем очищение множества небольших областей и перерисовывание отдельных частей элемента. Хост-процесс приложения, в итоге, выполняет рендеринг всего элемента, со всем его содержимым, для каждого кадра, в целях управления прозрачностью, поэтому попытка оптимизировать производительность путем очищения небольших областей – это неэффективная стратегия, за исключением случаев, когда вы выполняете небольшое количество вызовов API для каждого кадра.
  • API отрисовки элемента canvas реализованы путем конверсии его в соответствующие вызовы Direct2D GPU. При таком подходе фигуры выводятся с автоматическим антиалиасингом. В результате, рисование фигуры, наподобие незаполненной окружности, и рисование той же окружности с заданным фоновым цветом, не приводит к очистке каждого пикселя. Для того, чтобы эффективно очистить пиксели, используйте команду clearRect для области, которая немного больше, чем фигура. Это одна из причин, по которой очистка всего элемента и перерисовка каждого кадра часто оказывается самым простым решением.
  • Для того чтобы задать в элементе canvas фоновое изображение (то есть, вам не придется каждый раз его перерисовывать), вы можете использовать свойство canvas.style.backgroundImage с подходящим URI для изображения
  • Используйте метод ) для объекта ) для содержимого элемента.
  • При использовании drawImage, вам может понадобиться подождать какое-то время, пока необходимое изображение загрузится с использованием подобного кода:
     var img = new Image();
    img.onload = function () { myContext.drawImage(myImg, 0, 0); }
    myImg.src = "myImageFile.png";
    
  • Хотя другие графические API видят окружность как особый случай эллипса (с одними и теми же параметрами радиусов x и y), функция arc элемента canvas работает только с окружностями. К счастью, небольшое использование масштабирования упрощает рисование эллипсов, как показано ниже. Обратите внимание на то, что мы используем команды save и restore, таким образом, команда scale применяется только к arc. Она не воздействует на stroke, который используется из main. Это важно, так как если показатель масштабирования все еще действует, когда вы вызываете stroke, ширина линии будет меняться вместо того, чтобы оставаться постоянной.
    var img = new Image();
    img.onload = function () { myContext.drawImage(myImg, 0, 0); }
    myImg.src = "myImageFile.png";
    function arcEllipse(ctx, x, y, radiusX, radiusY, startAngle, endAngle, anticlockwise) {
    //Используем меньший радиус как базу и растягиваем другой	
    
    var radius = Math.min(radiusX, radiusY);	
    var scaleX = radiusX / radius;	
    var scaleY = radiusY / radius;	
    ctx.save();
    ctx.scale(scaleX, scaleY);
    
    //Обратите внимание на то, что центральная точка должна учитывать масштабирование	
    ctx.arc(x / scaleX, y / scaleY, radius, startAngle, endAngle, anticlockwise);
    ctx.restore();	
    }	
     
  • Копируя пиксельные данные из видео, возможно с использованием canvas динамически манипулировать видеоданными (не влияя на источник, конечно). Это полезная техника, даже учитывая то, что она интенсивно использует процессор. По этой причине, однако, такой подход может не работать нормально на маломощных устройствах.
  • Вот пример покадровой манипуляции с видео, техника, которая отлично освещена в блоге команды разработки Windows, в сообщение "Прямая манипуляция пикселями в canvas"Кроме того, обратитесь к материалу http://beej.us/blog/data/html5s-canvas-2-pixel/ (http://blogs.windows.com/windows/archive/b/developers/archive/2011/02/15/canvas-direct-pixel-manipulation.aspx). В упражнении к этой лекции VideoEdit, файл default.html содержит в теле элементы video и canvas:

    <video id="video1" src="ModelRocket1.mp4" muted style="display: none"></video>
    <canvas id="canvas1" width="640" height="480"></canvas>
    

    В коде (js/default.js), мы вызываем функцию startVideo из обработчика активации. Эта функция запускает воспроизведение видео и использует requestAnimationFrame для выполнения пиксельной манипуляции для каждого видеокадра:

    function startVideo() {	
    video1 = document.getElementById("video1");	
    canvas1 = document.getElementById("canvas1");
    ctx = canvas1.getContext("2d");	
    
    video1.play();
    requestAnimationFrame(renderVideo);
    }
    
    function renderVideo() {
    //Копируем кадр из видео в canvas 
    ctx.drawImage(video1, 0, 0, canvas1.width, canvas1.height);
    
    //Получаем кадр в виде пиксельных данных
    var imgData = ctx.getImageData(0, 0, canvas1.width, canvas1.height);
    var pixels = imgData.data;
    
    //Обходим пиксели, обрабатывая их так, как нам нужно 
    var r, g, b;
    
    for (var i = 0; i < pixels.length; i += 4) {
    r = pixels[i + colorOffset.red];	
    g = pixels[i + colorOffset.green];	
    b = pixels[i + colorOffset.blue];	
    
    // Здесь создается негативное изображение	
    pixels[i + colorOffset.red] = 255 - r;	
    pixels[i + colorOffset.green] = 255 - g;
    pixels[i + colorOffset.blue] = 255 - b;	
    }	
    
    //Копируем измененные пиксели в canvas
    ctx.putImageData(imgData, 0, 0);
    //Запрашиваем следующий кадр
    requestAnimationFrame(renderVideo);
    }
     

    Страница в этом примере содержит скрытый видеоэлемент (style="display: none"), в котором запускается воспроизведение при загрузке страницы (video1.play()). В цикле requestAnimationFrame, текущий кадр из видео копируется в canvas (drawImage) и пиксели кадра копируются (getImageData) в буфер imgData. Затем мы обходим этот буфер и инвертируем цветовую информацию, создавая, таким образом, фотографический негатив изображения (альтернативная формула для перевода изображения в цветовой режим оттенков серого показана в комментариях и опущена выше). Затем мы копируем полученные пиксели обратно в canvas (putImageData), таким образом, когда мы возвращаемся, негатив изображения выводится на экран.

    Повторюсь, подобные операции интенсивно используют процессор и обычно не подлежат ускорению с помощью GPU, то есть, могут выполняться не очень хорошо на маломощных устройствах (однако, не забудьте запустить Release build (построении Выпуска) программы за пределами отладчика для оценки производительности). Гораздо лучше будет написать DLL для реализации видеоэффектов, там, где это возможно, как обсуждается в разделе "Применение видеоэффектов" ниже. Тем не менее, об этой технике полезно знать. Что на самом деле происходит, так это то, что вместо рисования каждого кадра с помощью вызовов API, мы просто используем видео в качестве источника данных. Мы можем, если захотим, украсить canvas любым другим способом, прежде чем возвращаться из функции ) на сайте разработчиков Mozilla, которыйди намически делает фоновые пиксели зеленого цвета в видеокадре прозрачными, в итоге, элемент img, расположенный под видео, становится видимым сквозь видео, выступая в роли фона. Тот же подход можно использовать для наложения двух видео, в итоге, то видео, которое будет расположено ниже, станет фоном вместо статического изображения. Опять же, помните о производительности маломощных устройств; вы можете решить предоставить параметр, посредством которого пользователь сможет отключить подобные дополнительные эффекты.

    Проигрывание видео и отложенная загрузка

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

    <video src="media/ModelRocket1.mp4" controls loop autoplay></video> 

    Как обычно, мы не будем повторять то, что можно найти среди спецификаций W3C по тегам . Спецификации позволяют узнать о свойствах, методах и событиях этих элементов. Обратите особое внимание на сводные данные по событиям в разделе 4.8.10.15 (http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#event-definitions), и то, что большинство свойств и методов и для того и для другого можно найти в разделе о медиа-элементах, 4.8.10 (http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#media-elements). Обратите внимание на элемент ), больше мы не будем на нем здесь останавливаться.

    Так же полезно понимать, что video и audio тесно связаны, так как они являются частью оной и той же спецификации. На самом деле, если вы просто хотите проиграть звуковую дорожку видеоклипа, вы можете использовать объект Audio в JavaScript:

     //Проигрывание лишь звуковой дорожки видеоклипа	
    var movieAudio = new Audio("http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4");
    
    movieAudio.load();	
    movieAudio.play();	
    

    Для любого видео-элемента вы можете задать ширину и высоту для управления размером области воспроизведений (вплоть до 100% для полноэкранного воспроизведения). Это важно, когда ваше приложение переключается между режимами просмотра и вы, вероятно, имеете CSS-стили видеоэлемента в различных медиа-запросах. Кроме того, если у вас есть элемент управления для полноэкранного воспроизведения, просто сделайте размеры видео такими же, как размер окна просмота (и после вызова ), если приложение находится в прикрепленном режиме). В дополнение, когда вы создаете видеоэлемент с атрибутом controls, у него автоматически появится элемент управления для перевода в полноэкранный режим, в правом углу, который делает именно то, что нужно для приложений Магазина Windows:

    Коротко говоря, вам не нужно делать чего-то особенного для того, чтобы это работало. Когда видео отображается в полноэкранном режиме, похожая кнопка (или клавиша Esc) позволяет вернуться к обычному режиму просмотра приложения.

    Примечание. Если вам интересно, элементы audio и video не предоставляют каких-либо псевдо-селекторов CSS для стилизации панели инструментов. Как сказала дошкольная учительница моего сына (в отношении раздачи фруктового мороженного, но такой подход работает и здесь), "Вы получаете то, что получаете, вы не столкнетесь с истерикой и вы счастливы". Если вы хотите сделать что-то особенное с этими элементами управления, вам нужно выключить элементы по умолчанию и предоставить собственные элементы управления, которые будут соответствующим образом вызывать методы элемента.

    Реализуя собственные элементы управления, убедитесь в том, что установили тайм-аут для их скрытия (либо скрывайте их, либо изменяйте их z-index), когда они не используются. Это особенно важно, если у вас есть кнопка для перевода видео в полноэкранный режим, как та, что имеется во встроенном наборе элементов, с помощью которой вы изменяете размер элемента в соответствии с разрешением экрана. Когда вы выполняете это, Windows автоматически обнаруживает, что видео выводится в полноэкранном режиме и выполняет некоторую оптимизацию производительности, но это не делается, если какие-то еще элементы находятся поверх видео. Хорошая идея – отключать любую выполняемую анимацию и отключать ненужные фоновые процессы, наподобие рабочих веб-процессов.

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

    mediaControl = Windows.Media.MediaControl;	
    mediaControl.addEventListener("soundlevelchanged", soundLevelChanged, false);
    mediaControl.addEventListener("playpausetogglepressed", playpause, false);
    mediaControl.addEventListener("playpressed", play, false);	
    mediaControl.addEventListener("stoppressed", stop, false);	
    mediaControl.addEventListener("pausepressed", pause, false);
     

    Я так же упоминал, что вы можете отложить загрузку видео до того момента, как оно понадобится, и вместо него показать изображение для предварительного просмотра. Это можно реализовать с помощью атрибута poster, значением которого является изображение, которое нужно использовать:

    <video id="video1" poster="media/rocket.png" width="640" height="480"></video>
    
    var video1 = document.getElementById("video1");	
    var clickListener = video1.addEventListener("click", function () {	
    video1.src = "http://www.kraigbrockschmidt.com/downloads/media/ModelRocket1.mp4";
    
    video1.load();	
    
    // Удалим прослушиватель для предотвращения пересечения с элементами управления видео
     video1.removeEventListener("click", clickListener);
    
    video1.addEventListener("click", function () {
    video1.controls = true;	
    video1.play();	
    });	
    });	
     

    В данном случае я не использую preload="true" и не задаю src, в итоге ничего не загружается до прикосновения к видео. Когда происходит прикосновение, прослушиватель удаляется, включаются собственные элементы управления видео и начинается воспроизведение. Это, конечно, обходной метод, чаще вы будете исопользовать preload="true" controls src="..." непосредственно в видеоэлементе, в то время, как атрибут poster будет обрабатывать изображения предварительного просмотра.

    Отключение скринсейверов и экрана блокировки при воспроизведении

    При воспроизведении видео, особенно – полноэкранном, важно отключить любые автоматические тайм-ауты, которые могут очистить экран или заблокировать устройство. Это можно выполнить с помощью объекта ). Прежде чем начинать воспроизведение, создайте экземпляр этого объекта и вызовите его метод requestActive.

    var displayRequest = new Windows.System.Display.DisplayRequest();
    displayRequest.requestActive();
     

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

    Расширения API видеоэлемента

    Помимо стандартов HTML5 для элементов video, в Windows 8 к нему добавлены некоторые доополнительные свойства и методы, как показано в следующей табилце и описано на странице "Видеоэлемент" (http://msdn.microsoft.com/library/windows/apps/hh465962.aspx). Кроме того, взгляните на пример "Воспроизведение мультимедиа в HTML" (http://code.msdn.microsoft.com/windowsapps/Media-Playback-Sample-3bdbe7c9), где вы можете найти примеры их использования.

    Свойства Описание
    msHorizontalMirror Логическое значение, которое задает горизонтальное отражение воспроизведения. Это особенно полезно, когда источником видеоэлемента являются данные с камеры, что позволяет пользователю видеть изображение в верной ориентации. Посмотрите примечания к свойству enclosureLocation в разделе "Выбор устройства захвата мультимедиа" ниже.
    msZoom Логическое значение, указывающее на то, разрешено ли видеоэлементу вписываться в пространство дисплея обрезая верхние/нижние или левые/правые части (если имеет значение ).
    msIsLayoutOptimalForPlayback (onMSVideoOptimalLayoutChanged) Логическое значение, которое указывает имеет ли видео наилучшую производительность воспроизведения на основе его макета. Когда это свойство меняется, вызывается событие ) и "Производительность аудио и видео" (http://msdn.microsoft.com/library/windows/apps/hh848311.aspx).
    msIsStereo3D Логическое значение, которое показывает, является ли источник видео трехмерным (на основе метаданных видеофайла). Поддерживает ли подобную функцию система, можно определить посредством ). Приложения так же могут прослушивать событие WinRT Windows.Graphics.Display.DisplayProperties.stereoEnabledChanged (http://msdn.microsoft.com/library/windows/apps/windows.graphics.display.displayproperties.stereoenabledchanged.aspx) для того, чтобы узнать об изменениях возможностей. Для того, чтобы узнать подробностей, касающихся других особенносте стереоскопического 3D-режима, обратитесь к материалу "Включение воспроизведения видео в стереорежиме" (http://msdn.microsoft.com/library/windows/apps/hh452749.aspx), и к Сценарию 5 примера "Воспроизведение мультимедиа в HTML"
    msStereo3DRenderMode Может принимать значение mono (по умолчанию) или stereo, таким образом приложения могут управлять воспроизведением (смотрите подробности выше)
    msStereo3DPackingMode Может иметь значение none (2D-режим по умолчанию), topbottom, или sidebyside; эта настройка доступна приложениям, когда метаданные видео не отражают ориентацию, которую нужно использовать (смотрите выше).
    msRealtime Активирует уменьшение первоначальной задержки воспроизведения настолько, насколько это возможно. Это важно для приложений двусторонней связи, например, так же для игровых чатов, но пользоваться этим следует осмотрительно. Для того, чтобы узнать подробности, обратитесь к материалу "Активация воспроизведения с низкой задержкой" (http://msdn.microsoft.com/library/windows/apps/hh452742.aspx) и к примеру "Связь в реальном времени" (http://code.msdn.microsoft.com/Simple-Communication-Sample-eac73290).Активирует уменьшение первоначальной задержки воспроизведения настолько, насколько это возможно. Это важно для приложений двусторонней связи, например, так же для игровых чатов, но пользоваться этим следует осмотрительно. Для того, чтобы узнать подробности, обратитесь к материалу "Активация воспроизведения с низкой задержкой" (http://msdn.microsoft.com/library/windows/apps/hh452742.aspx) и к примеру "Связь в реальном времени" (http://code.msdn.microsoft.com/Simple-Communication-Sample-eac73290).
    msPlayToDisabled, msPlayToPrimary, msPlayToSource Свойства, связанные с функцией Windows по воспроизведению на целевых объектах (Windows PlayTo). Смотрите раздел "Воспроизведение на целевых объектах" в конце этой лекции. Обратите внимание на то, что это доступно так же для элементов img и audio.
    msAudioTracks Массив описаний аудиозаписей для поддержки дополнительных языков или других записей (то есть – комментариев). Установите ) и к сценарию 2 примера "Воспроизведение мультимедиа в HTML".
    msAudioCategory Идентифицирует вид аудио, проигрываемого в видеозаписи. Смотрите раздел "Управление воспроизведением и фоновое аудио" ниже для того, чтобы узнать подробности. Обратите внимание на то, что установка этого свойства в значение "Communications" так же установит тип устройства в значение "Communications" и переключит msRealtime в значение true.
    msAudioDeviceType Задает выходное устройство, на которое будет отправлено аудио, смотрите "Расширения API аудиоэлемента"."
    Методы Описание
    msFrameStep (onMSVideoFrameStepCompleted) Перемещает видео на одинк кадр вперед или назад. Событие onMSVideoFrameStepCompleted вызывается, когда перемещение завершено.
    msInsertVideoEffect msInsertAudioEffect msClearEffects Добавляет или удаляет видеоэффекты при воспроизведении (смотрите ниже). Все это доступно для видео; msInsertVideoEffect не доступно для аудиоэлементов.
    msSetMediaProtectionManager Используется для DRM и с видео, и с аудио, смотрите раздел "Потоковая передача данных с сервера и DRM" ближе к концу этой лекции.
    msSetVideoRectangle Задает размер внутренней прямоугольной области в видео.
    onMSVideoFrameStepCompleted (event) Происходит при изменении формата видео

    Атрибут source и пользовательские кодеки

    Элементы видео (и аудио) могут использовать атрибут HTML5 ), это не большая проблема для приложений Магазина Windows. Однакое, использование source все еще полезно, так как этот атрибут позволяет идентифицировать конкретный кодек для источника медиаданных:

    <video controls loop autoplay>
    <source src="video1.vp8" type="video/webm" />
    </video>
     

    Это важно, когда вы хотите предоставить пользовательский кодек для приложения посредством Windows.Media.MediaExtensionManager, что описано в разделе "Пользовательские кодеры/декодеры и обработчики схем" ниже в этой лекции, так как кодек идентифицирует расширение для загрузки и применения при декодировании. Я показал здесь в качестве примера WebM, так как он не доступен напрямую приложениям для Магазина Windows (хотя присутствует в Internen Explorer). Когда исполняется хост-процесс, приложение для Магазина Windows, содержащее вышеописанный элемемент video, будет выполнять поиск подходящего декодера для заданного параметра type.

    Применение видеоэффектов

    Вышеприведенная таблица показывает, что у видеоэлемента есть методы msInsertVideoEffect и msInsertAudioEffect. WinRT предоставляет встроенный эффект стабилизации видео, который легко применить к элементу. Это показано в Сценарии 3 примера "Мультимедийные расширения" (), где одно и то же видео проигрывается с использованием эффекта и без него, у стабилизированного видео отключен звук:

    vidStab.msClearEffects(); 
    vidStab.muted = true; 
    vidStab.msInsertVideoEffect(Windows.Media.VideoEffects.videoStabilization, true, null);
     

    Пользовательские эффекты, как показано в Сценарии 4 примера, применяются в виде отдельных динамически связываемых библиотек (DLL), обычно написанных на C++ для лучшей производительности, и включенных в пакет приложения, так как приложения для Магазина Windows могут устанавливать DLL только для собственного использования, а не для общесистемного доступа. В примере вы найдете проекты DLL для перевода изображения в оттенки серого, инверсии и применения геометрических эффектов, где у последних есть три параметра – для эффекта "рыбьего глаза" (fisheye), сжатия (pinch) и деформации (warp). В файле js/customEffect.js вы можете видеть, как применяются эти эфекты, в первом параметре msInsertVideoEffect, который является строкой и идентифицирует эффект, экспортируемый DLL (смотрите, например, файл InvertTransform.idl в проекте InvertTransform):

    vid.msInsertVideoEffect("GrayscaleTransform.GrayscaleEffect", true, null);
    
    vid.msInsertVideoEffect("InvertTransform.InvertEffect", true, null);
     

    Второй параметр msInsertVideoEffect, кстати, показывает, нужно ли применять эффект, обычно он имеет значение true. Третий параметр называется конфигурация (config), он содержит дополнительные сведения, которые передаются в эффект. В случае с геометрическими эффектами в примере, этот параметр задает конкретный вариант эффекта:

    var effect = new Windows.Foundation.Collections.PropertySet();	
    effect["effect"] = effectName;	
    vid.msClearEffects();	
    vid.msInsertVideoEffect("PolarTransform.PolarEffect", true, effect);
     

    Здесь effectName может принимать значения "Fisheye", "Pinch", или "Warp".

    Аудиоэффекты, не показанные в примере, применяются так же, с помощью msInsertAudioEffect (с теми же параметрами). Обратите внимание на то, что каждый элемент может иметь не более двух эффектов в потоке. Элемент video может иметь два видеоэффекта и два аудиоэффекта, элемент audio может иметь два аудиоэффекта. Если вы попытаетесь добавить больше, метод выдаст исключение. Поэтому полезно вызывать msClearEffects перед добавлением эффектов.

    Подробности об эффектах и других расширениях мультимедиа вы можете найти в материале "Применение расширений мультимедиа" (http://msdn.microsoft.com/library/windows/apps/hh700365.aspx).

    Обзор мультимедиа-серверов

    Во многих домашних хозяйствах, и в моем тоже, имеется один или большее количество мультимедиа-серверов, доступных в локальной сети, с которых приложения могут воспроизводить мультимедийные данные. Добраться до этих серверов можно с помощью еще одного свойства ). Как и в слудчае с другими известными папками, это просто объект StorageFolder, посредством которого можно перечислять дополнительные папки и файлы или применять запросы к ним. В данном случае, если вы вызываете его метод getFoldersAsync, вы получаете список доступных серверов, каждый из которых представлен собственным объектом StorageFolder. Здесь вы можете использовать файловые запросы, как было описанов в лекции 2, для поиска мультимедийных да нных интересующих вас типов, или использовать критерии поиска, заданные пользователем. Вот пример, посвященный этому: "Клиент мультимедиа-сервера" (http://code.msdn.microsoft.com/windowsapps/Media-Server-sample-fffbe490).

    Воспроизведение и микширование звука

    Как и в случае с видеоданными, элемент audio предоставляет собственные возможности по воспроизведению, в том числе – элементы управления, циклическое воспроизведение и автовоспроизведение:

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

    Опять же, как описано выше, одни и те же спецификации W3C применимы и к элементу video, и к элементу audio. Уже известный код для проигрывания лишь звуковой дорожки видеофайла, мы можем использовать для проигрывания аудиофайла:

    var sound = new Audio("media/SpringyBoing.mp3");
    sound1.msAudioCategory = "SoundEffect";	
    sound1.load(); //Для предварительной загрузки данных	
    sound1.play(); //В любое время позже	
     

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

    Как и в случае с видео, для приложения, выполняющего воспроизведение звука, важно соответствующим образом реагировать на события, исходящие из объекта ), в особенности на события playpressed, pausepressed, stoppressed, и playpausetogglepressed. Это позволяет пользователю управлять воспроизведением с помощью аппаратных кнопок, которые можно использовать при воспроизведении музыки, например. Однако, вы можете не применять обработку этих событий, например, при воспроизведении игровых звуков.

    Говоря о воспроизведении звука, интересно рассмотреть вопрос о смешивании нескольких звуков, что обычно нужно в играх. Важно понимать, что каждый элемент И, конечно, я играю на гитаре и пою главную партию в этой живой записи, вместе с моим другом Тедом Катлером. Песня "Who is Sylvia?" написана другим моим другом, Дж. Дональдом Уолтерсом, на стихи Шекспира.

    var sound1 = new Audio("media/SpringyBoing.mp3");
    sound1.load(); //Для предварительной загрузки данных
    
    //Фоновая музыка	
    var sound2 = new Audio();	
    sound2.msAudioCategory = "ForegroundOnlyMedia"; //Установим перед установкой src	
    sound2.src = "http://www.kraigbrockschmidt.com/mp3/WhoIsSylvia_PortlandOR_5-06.mp3";
    
    sound2.loop = true;	
    sound2.volume = 0.5; //50%;	
    sound2.play();	
    
    document.getElementById("btnSound").addEventListener("click", function () {
    //Сбрасываем позицию, если уже воспроизводим	
    sound1.currentTime = 0;	
    sound1.play();	
    });	
     

    Загрузив звук, воспроизводимый при касании, мы знаем, что можем воспроизвести его в любое время. При запуске воспроизведения, полезно сбросить currentTime в значение 0, таким образом, звук всегда будет воспроизводиться сначала.

    Вопросы о микшировании, особенно в играх, касаются управления различными звуками без знания наперед времени, когда они будут смешиваться. Вам может быть нужно, например, наложить друг на друга воспроизведение одного и того же звука, с различным временем начала, но объявлять три аудиоэлемента с одним и тем же источником непрактично. Представленная техника касается использования "ротации каналов" ("rotating channels"), как описано здесь: http://ajaxian.com/archives/html5-audio-tutorial-rotating-channels. В итоге получается следующее:

  • Объявляем элементы audio для каждого звука (с установкой preload="auto").
  • Создаем пул (массив) объектов audio для необходимого количества каналов
  • Для воспроизведения звука
  • Получаем доступный объект Audio из пула.
  • Устанавливаем его атрибут src в соответствии с одним из соответствующих элементов audio с предварительно загруженными данными.
  • Вызываем метод play этого объекта из пула.
  • Как обнаружили звукорежиссеры фильмов, нет особенного смысла проигрывать одновременно слишком много звуков, так как звучание становится слишком "грязным". В итоге, вам не понадобится больше пары десятков каналов.

    Подсказка. Нужны звуки для приложения? Загляните на http://www.freesound.org/.

    Расширения API аудиоэлемента

    Как и в случае с элементом video, и для элемента audio доступны некоторы расширения, в частности те, что можно использовать для управления эффектами (msInsertAudioEffect), DRM (msSetMediaProtectionManager), для воспроизведения на целевых объектах (msPlayToSource, и так далее.), msRealtime, и msAudioTracks, как перечислено раньше в разделе о расшираниях API для видеоэлемента. На самом деле, каждое расширение API для аудио существует и для видео, но два из них имеют особую важность для элементов audio: msAudioDeviceType позволяет приложению определить, на какое выходное устройство осуществляется отправка звука: "Console" (по умолчанию) и "Communications". Это способ, благодаря которому приложение знает, что оно участвует в сеансе связи (наподобие чата), что не связано с воспроизведением мультимедийных аудиоклипов.

    msAudioCategory идентифицирует тип проигрываемой аудиозаписи (смотрите таблицу в следующем разделе). Это очень важно для идентификации того, следует ли продолжать воспроизведение музыки в фоновом режиме (тем самым предотвращая перевод приложения в приостановленный режим), как описано далее. Обратите внимание на то, что следует всегда устанавливать это свойство перед установкой src, и на то, что установка режима "Communications" так же устанавливает тип устройства на "Communications" и приводит к установке msRealtime в true.

    Обратите внимание на то, что несмотря на схожесть значений в этих свойствах, msAudioDeviceType предназначено для выбора выходного устройства, в то время как msAudioCategory идентифицирует тип аудиозаписи, которая воспроизводится через любое устройство. Аудио с коммуникационной категорией, например, может воспроизводиться на консольном устройстве, а мультимедийное аудио – на коммуникационном устройстве. За этими двумя свойствами стоят разные концепции.

    Управление воспроизведением и фоновое аудио

    Для того, чтобы рассмотреть различные виды воспроизведения аудио, обратимся к примеру "Средство управления воспроизведением msAudioCategory" (http://code.msdn.microsoft.com/windowsapps/Playback-Manager-e6526e67). Я не привожу здесь скриншот, так как пример лишь работает с аудио, и там особенно нечего показывать! ВВместо этого позвольте мне изложить особенности поведения различных его сценариев следующей таблице, а так же – некоторые категории, которые не представлены в примере, но могут быть использованы в ваших приложениях. В каждом сценарии вам сначала нужно выбрать аудиофайл с помощью средства выбора файлов:

    Сценарий msAudioCategory Описание
    1 BackgroundCapableMedia Воспроизводит выбранный аудиофайл, и когда приложение видимо, и в фоновом режиме, в том числе тогда, когда пользователь находится на Рабочем столе, на Начальном экране или на экране блокировки. Приложение не приостанавливается, находясь в фоновом режиме, в этом можно убедиться посредством Диспетчера задач. Это обычно исопользуется для воспроизведения локальных списков воспроизведения, локальных или потоковых медиафайлов, музыкальных видео и так далее. Использование этой категории требует объявления в манифесте и наличия обработчиков аппаратных кнопок управления воспроизведением.
    2 Communications Как и в случае BackgroundCapableMedia, воспроизведение звука продолжается и когда приложение находится в фоновом режиме. Используйте это для чатов, VoIP-приложений и так далее.
    3 Other (по умолчанию для элементов audio) Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане, микшируется с фоновым аудио, когда приложение переходит в фоновый режим, воспроизведение приостанавливается.
    4 ForegroundOnlyMedia Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане. Воспроизведение приостанавливается, когда приложение переходит в фоновый режим. Когда воспроизводится аудио из этой категории, фоновое аудио отключается.
    5 Alert Проигрывает выбранный аудиофайл, когда приложение находится на переднем плане, ослабляет фоновое аудио. Используется для оповещений, наподобие звонков, и для системных сообщений.
    n/a GameMedia Используется для окружающей музыки в играх.
    n/a GameEffects Используется для игровых звуковых эффектов, предназначенных для смешивания с воспроизводимыми звуками (все немузыкальные звуки).
    n/a SoundEffects Другие звуковые эффекты (за пределами игр), которые предназначены для смешивания с воспроизводимым звуком, такие, как короткие звонки, писки, стуки, бульканья, которые сопутствуют неким действиям, но не являются оповещениями.

    Когда речь идет об отдельном звуковом потоке, между некоторыми из этих категорий нет особой разницы. Действительно, как показано в таблице, звуки разных категорий по-разному воздействуют на другие звуковые потоки, проигрываемые одновременно с ними. Для этой цели в Windows SDK сделан необычный ход: предоставлен второй пример, идентичный вышеописанному, "Дополнительный пример для средства управления воспроизведением" (http://code.msdn.microsoft.com/windowsapps/Playback-Manager2-55c5b86d). Это позволяет вам запустить данные приложения одновременно (одно – в прикрепленном режиме, другое в заполняющем, или одно, либо оба, в фоновом режиме) и воспроизводить аудио различных категорий, наблюдая их взаимодействие.

    Как комбинируются различные аудиопотоки, рассматривается в документе "Воспроизведение аудио в приложениях для Windows 8" (http://msdn.microsoft.com/library/windows/hardware/hh770517.aspx). Однко, самое важное, это чтобы вы присваивали каждому аудиопотоку наиболее соответствующую ему категорию. Эти категории помогают средству управления воспроизведением правильно микшировать звуковые потоки, основываясь на ожиданиях пользователя. Речь идет и о нескольких потоках в одном приложении, и о потоках аудио, поступающих от разных приложений (с ограничением количества приложений, которые могут одновременно воспроизводить аудио в фоновом режиме). Например, пользователи ожидают, что будильник, важная форма оповещения, временно приглушит другие аудиопотоки. Похожим образом, пользователи ожидают, что аудиопоток от приложения переднего плана имеет преимущество перед потоком той же категории, воспроизводимым в фоновом режиме. Как разработчик, поэтому, избегайте развлечений с категориями. Просто на значайте наиболее подходящие категории вашим аудиопотокам и позвольте средству управления воспроизведением делать свою работу с аудио, которое поступает из всех источников и создает последовательный опыт взаимодействия пользователя и системы в целом.

    Установка категории для любого элемента audio, заключается в простом задании его атрибута msAudioCategory. Каждый сценарий в примере выполняет это одинаково, устанавливая категорию перед установкой атрибута src (здесь показан код из js/backgroundcapablemedia.js):

    audtag = document.createElement('audio'); 
    audtag.setAttribute("msAudioCategory", "BackgroundCapableMedia");
     audtag.setAttribute("src", fileLocation);
     

    Конечно, вы можете сделать то же самое в разметке. Вот примеры:

    <audio id="audio1" src="song.mp3" msAudioCategory="BackgroundCapableMedia"></audio>
    <audio id="audio2" src="voip.mp3" msAudioCategory="Communications"></audio>
    <audio id="audio3" src="lecture.mp3" msAudioCategory="Other"></audio>
     

    Однако, в случае с BackgroundCapableMedia and Communcations недостаточно лишь установить категорию: вам так же нужно задать расширение фоновой задачи в манифесте. Это просто сделать на закладке Объявления (Declarations) редактора манифеста:

    Во-первых, выберите Фоновые задачи (Background tasks) из выпадающего списка Доступные объявления (Available declarations). Затем установите флаг Аудио (Audio) в группе Поддерживаемые типы задач (Supported task types) и укажите начальную страницу (Start page) в разделе параметров приложения (App settings). Начальная страница не особенно важна для фонового аудио (так приложение никогда не будет запущено извне для этой цели), но это нужно для соответствия правилам заполнения манифеста.

    В XML-файле манифеста эти объявления выглядят следующим образом, взгляните на них:

    <Application Id="App" StartPage="default.html">
    <!-- ... -->
    <Extensions>
    <Extension Category="windows.backgroundTasks" StartPage="default.html">
    <BackgroundTasks>
    <Task Type="audio" />
    </BackgroundTasks>
    </Extension>
    </Extensions>
    </Application>
     

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

    Как это сделать, показано в примере о средстве управления воспроизведением. Вот код (часть опущена) из файла js/communication.js:

    mediaControl = Windows.Media.MediaControl;
    
    mediaControl.addEventListener("soundlevelchanged", soundLevelChanged, false);
    mediaControl.addEventListener("playpausetogglepressed", playpause, false);	
    mediaControl.addEventListener("playpressed", play, false);	
    mediaControl.addEventListener("stoppressed", stop, false);	
    mediaControl.addEventListener("pausepressed", pause, false);	
    
    
    // переменная audtag это глобальный аудиоэлемент для страницы
    function playpause() {	
    if (!audtag.paused) {
    audtag.pause();	
    } else {	
    audtag.play();	
    }	
    }	
    function play() {
    audtag.play();
    }
    
    function stop() {
    // Здесь ничего не делается
    }
    
    function pause() {
    audtag.pause();
    }
    function soundLevelChanged() {	
    //Перехватываем уведомление SoundLevel и определяем его состояние.
    //Если звук выключен, приостанавливаем воспроизведение.	
    var soundLevel = Windows.Media.MediaControl.soundLevel;	
    //Здесь ничего не делается, параметры приведены для показа содержимого перечисления 
    switch (soundLevel) {
    case Windows.Media.SoundLevel.muted:
    break;
    case Windows.Media.SoundLevel.low:
    break;
    case Windows.Media.SoundLevel.full:
    break;
    }
    appMuted();
    }
    function appMuted() {	
    if (audtag) {	
    if (!audtag.paused) {
    audtag.pause();	
    }	
    }	
    }	
     

    С технической точки зрения, обработчик для события soundLevelChanged здесь не требуется, но другие четыре нужны. Подобная минимальная реализация – это часть упражнения к этой лекции AudioPlayback, код которого так же использует флаг MediaControl.isPlaying для настройки кнопки проигрывание / пауза в пользовательском интерфейсе проигрывателя аудио (смотрите в следующем разделе).

    Вот некоторые дополнительные замечания, касающиеся фонового аудио:

  • Причина, по которой мы различаем события paypressed, pausepressed и playpaysepressed заключается в поддержке разнообразного аппаратного обеспечения, при этом некоторые устройства имеют раздельные кнопки запуска воспроизведения и постановки на паузу, а у некоторых предусмотрена лишь одна кнопка и для того, и для другого.
  • Если воспроизведение аудио приостановлено, приложение, воспроизводящее фоновое аудио, будет приостановлено, как и прочие, но если пользователь нажмет кнопку воспроизведения, приложение возобновит работу и продолжит проигрывание аудио.
  • Использование функции фонового воспроизведения аудио тщательно оценивается при отправке приложения в Магазин Windows. Если вы попытаетесь проигрывать беззвучную запись для того, чтобы предотвратить приостановку приложения, приложение не пройдет сертификацию.
  • Приложения фонового воспроизведения аудио должны осторожно использовать сетевое соединение для приема потоковых данных для поддержки состояния низкого потребления энергии, которое называется режим ожидания с подключением (connected standby). Подробности вы можете узнать в материале "Создание приложений фонового воспроизведения мультимедиа, экономящих энергию" (http://msdn.microsoft.com/library/windows/desktop/jj247568.aspx).
  • Посмотрим теперь на еще одну важную причину, по которой мы должны реализовывать события элементов управления мультимедиа: пользовательский интерфейс, который Windows отображает в ответ на нажатия аппаратных кнопок.

    Пользовательский интерфейс управления воспроизведением

    Как было упомянуто в предыдущем разделе, приложениям, которые воспроизводят фоновое аудио, нужно предоставлять обработчики событий объекта MediaControl. Благодаря этому пользовали могут управлять воспроизведением с помощью аппаратных кнопок (они встроены во многие устройства, в том числе – клавиатуры, пульты дистанционного управления) без необходимости переключаться на приложение. Это особенно важно, так как фоновое аудио продолжает воспроиизводиться не только тогда, когда пользователь переключается к другому приложению, но и тогда, когда пенеходит на Начальный экран, и на рабочий стол, или блокирует устройство.

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

    На изображениях вы можете видеть имя приложения, по умолчанию отображаемое в интерфейсе, взятое из свойства Отображаемое имя (Display Name), из манифеста. Хотя это и применимо, в идеале аудиоприложению следует передавать подробные метаданные записи в ), который показывает, как получать сведения об альбоме для аудиозаписи, мы вернемся к этому позже.

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

    Вы можете заметить в вышеприведенных изображенийх, что кнопки перехода на следующую и предыдущую запись заблокированы. Это потому, что приложение не имеет прослушивателей для событий nexttrackpressed и previoustrackpressed объекта MediaControl. Мы увидим, как пользоваться ими, в следующем разделе. Есть, так же, и другие события, такие, как channeldownpressed, channeluppressed, fastforwardpressed, rewindpressed, recordpressed, и stoppressed, хотя они и не представлены в интерфейсе.

    Последовательное воспроизведение аудиозаписей

    Приложения, которые воспроизводят аудиозаписи (такие, как музыку, аудиокниги или записи лекций) часто имеют некоторый список записей для последовательного воспроизведения, в особенности, когда приложение исполняется в фоновом режиме. В данном случае важно быстро начинать воспроизведение следующей записи, так как в противном случае Windows приостановит приложение через 10 секунд после завершения воспроизведения текущей записи. Для этой цели прослушивают событие ended элемента audio и устанавливают audio.src на следующую запись. В данном случае хорошая оптимизация заключается в использовании второго объекта Audio и установка его атрибута src после того, как первая запись начнет воспроизводиться. Таким образом, вторая запись будет предварительно загружена и готова к немедленому воспроизведению, таким образом, устраняя потенциальные задержки между записями при воспроизведении. Это реализовано в упражнении к этой лекции AudioPlayback, где я разделил одну песню на четыре сегмента для непрерывного воспроизведения. Я так же покажу здесь, как обрабатывать событии кнопок "Предыдущая запись" и "Следующая запись", вместе с установкой номера сегмента в качестве названия записи:

    var mediaControl = Windows.Media.MediaControl;	
    var playlist = ["media/segment1.mp3", "media/segment2.mp3", "media/segment3.mp3",
    "media/segment4.mp3"];	
    var curSong = 0;	
    var audio1 = null;	
    var preload = null;	
    
    document.getElementById("btnSegments").addEventListener("click", playSegments);
    audio1 = document.getElementById("audioSegments");
    preload = document.createElement("audio");
    
    function playSegments() {	
    //Всегда сбрасывайте прослушиватели событий объектов 
    WinRT для предотвращения дублирования и утечек памяти
    mediaControl.removeEventListener("nexttrackpressed", nextHandler);	
    mediaControl.removeEventListener("previoustrackpressed", prevHandler);	
    	
    curSong = 0;	
    
    //Приостановим другую музыку 
    document.getElementById("musicPlayback").pause();
    
    //Set up media control listeners setMediaControl(audio1);
    
    //Покажем элемент (изначально скрытый) и начнем воспроизведение
    audio1.style.display = "";
    audio1.volume = 0.5; //50%;
    playCurrent();
    
    //Предварительная загрузка следующая запись и готовность к переключению 
    var preload = document.createElement("audio"); preload.setAttribute("preload", "auto");
    preload.src = playlist[1];
    
    //Переключаемся на следующую запись, как только очередная окончится или 
    будет нажат кнопка "Следующая запись"
    audio1.addEventListener("ended", nextHandler);	
    mediaControl.addEventListener("nexttrackpressed", nextHandler);	
    }	
    }	
    function nextHandler () {
    curSong++;
    
    //Активируем кнопку "Предыдущая запись", если у нас есть
     хотя бы одна предыдущая запись	
    if (curSong > 0) {	
    mediaControl.addEventListener("previoustrackpressed", prevHandler);
    }	
    
    if (curSong < playlist.length) {
    //playlist[curSong] уже должен быть загружен
    playCurrent();
    
    //Установка следующей заранее загруженной композиции
    var nextTrack = curSong + 1;
    
    if (nextTrack < playlist.length) {
    preload.src = playlist[nextTrack];
    } else {
    preload.src = null;
    mediaControl.removeEventListener("nexttrackpressed", nextHandler);
    }
    }
    }
    
    function prevHandler() {	
    //Если уже проигрываем последнюю запись, 
    снова добавим обработчик кнопки "Следующая запись"
    if (curSong == playlist.length - 1) {	
    mediaControl.addEventListener("nexttrackpressed", nextHandler);	
    }	
    
    curSong--;
    
    if (curSong == 0) {
    mediaControl.removeEventListener("previoustrackpressed", prevHandler);
    }
    
    playCurrent();
    preload.src = playlist[curSong + 1]; //Это должно работать всегда
    }
    
    function playCurrent() {	
    audio1.src = playlist[curSong];	
    audio1.play();	
    mediaControl.trackName = "Segment " + (curSong + 1);
    }	
     

    При последовательном проигрывании записей, как здесь, из приложения, написанного на JavaScript и HTML, вы можете отметить небольшие паузы между записями, особенно, если первая запись напрямую переходит во вторую. Это существующие ограничения платформы, где существуют уровни между HTML-элементом audio и низкоуровневым API XAudio2, которое, в конечном счете, выполняет реальную работу. В какой-то мере вы можете смягчить этот эффект, например, вы можете организовать плавный переход одной записи в другую, или наложить третью запись на конец первой и начало второй. Так же вы можете использовать отрицательное значение смещения по времени для начала воспроизведения второй записи немного раньше, чем будет окончена первая. Но если вам нужен по-настоящему бесшовный переход между записями, вам нужно обойти элемент audio и использовать API XAudio2 из WinRT-компонента для непосредственного воспроизведения музыки. О том, как это сделать, идет речь в сообщении блога для разработчиков приложений для Windows 8: "Создание собственных компонентов среды выполнения Windows для разработки эффективных приложений" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/08/13/windows-metro.aspx).

    Вернуться к учебному плану