Опубликован: 10.04.2013 | Доступ: свободный | Студентов: 440 / 9 | Длительность: 16:52:00
Специальности: Программист
Лекция 6:

Списки воспроизведения

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >

Выбор устройства захвата мультимедиа

Взглянем теперь на Сценарий 2 (js/AdvancedCapture.js), он более или менее похож на Сценарий 1, но он позволяет вам выбирать конкретное устройство захвата. До настоящего момента мы пользовались лишь устройством по умолчанию, но вы не ограничены этим, конечно. Вы можете использовать API Windows.Devices.Enumeration (http://msdn.microsoft.com/library/windows/apps/windows.devices.enumeration.aspx) для получения списка устройств в классе интерфейсов устройств. В примере использован заранее определенный класс videoCapture:

function enumerateCameras() {
var cameraSelect = id("cameraSelect");
deviceList = null;
deviceList = new Array();
while (cameraSelect.length > 0) {
cameraSelect.remove(0);
}
//Перечисляем вебкамеры и добавляем их в список
var deviceInfo = Windows.Devices.Enumeration.DeviceInformation;
deviceInfo.findAllAsync(Windows.Devices.Enumeration.DeviceClass.videoCapture)
.done(function (devices) {
// Добавляем устройства в deviceList 
if (devices.length > 0) {
for (var i = 0; i < devices.length; i++) {
deviceList.push(devices[i]);
cameraSelect.add(new Option(deviceList[i].name), i);
}
//Выбираем первую вебкамеру
cameraSelect.selectedIndex = 0; 
initCaptureSettings();
} else {
// блокируем кнопки.
}
}, errorHandler);
}
 

Выбранные ID устройств затем копируются внутри initCaptureSettings в свойство MediaCaptureInitializationSetting.videoDeviceId:

 var selectedIndex = id("cameraSelect").selectedIndex; 
var deviceInfo = deviceList[selectedIndex]; 
captureInitSettings.videoDeviceId = deviceInfo.id;

Кстати, вы всегда можете получить ID устройства по умолчанию, воспользовавшись методами объекта Windows.Media.Devices.MediaDevice (http://msdn.microsoft.com/library/windows/apps/br226802.aspx) и прослушивая его события на предмет изменения устройств по умолчанию. Важно отметить, что DeviceInformation (в переменной deviceInfo выше) включает в себя свойство, которое называется enclosureLocation. Оно сообщает о том, направлена ли камера на пользователя, или от него, что вы можете использовать для поворота видео или фото так, чтобы их отображение соответствовало восприятию пользователя:

var cameraLocation = null;

if (deviceInfo.enclosureLocation) {
cameraLocation = deviceInfo.enclosureLocation.panel;
}

if (cameraLocation === Windows.Devices.Enumeration.Panel.back) {
rotateVideoOnOrientationChange = true;
reverseVideoRotation = false;
} else if (cameraLocation === Windows.Devices.Enumeration.Panel.front) {
rotateVideoOnOrientationChange = true;
reverseVideoRotation = true;
} else {
rotateVideoOnOrientationChange = false;
}
 

Сценарий 2 демонстрирует, так же, использование MediaCapture.addEffectAsync с эффектом перевода в оттенки серого, что показано на рис. 6.7., который реализован в DLL (проект GrayscaleTransform в решении). Это работает в точности так, как работало уже рассмотренное нами перекодирование, и вы можете обратиться к функциям addRemoveEffect и addEffectToImageStream в файле примера js/AdvancedCapture.js для того, чтобы увидеть подробности. Вы можете здесь заметить, что эти функции выполняют некоторое количество проверок с использованием значения MediaCaptureSettings.videoDeviceCharacteristic для того, чтобы убедиться, что эффект добавлен в верное место.

Сценарий 2 примера о захвате мультимедиа, где можно выбирать конкретное устройство захвата и применять эффект (Окно обрезано из скриншота большего размера). Вы достаточно внимательно посмотрели на этот рисунок, чтобы заметить, что я поменял гитары?

Рис. 6.7. Сценарий 2 примера о захвате мультимедиа, где можно выбирать конкретное устройство захвата и применять эффект (Окно обрезано из скриншота большего размера). Вы достаточно внимательно посмотрели на этот рисунок, чтобы заметить, что я поменял гитары?

Потоковое мультимедиа и целевые объекты воспроизведения

Грубым преуменьшением будет говорить, что потоковое мультимедиа популярно в наши дни. Как я упоминал во введении к лекции, один только Netflix занимает немалую долю полосы пропускания современного Интернета (и в моем доме – тоже). YouTube тоже не стоит в стороне – и ваше приложение так же может внести свой вклад в это дело!

Передача мультимедийных данных с сервера приложению это простой и наболее распространенный случай. Это происходит автоматически, когда вы устанавливаете атрибут src элементов audio или video на удаленный URI. Для того, чтобы улучшить этот процесс, у Microsoft есть Smooth Streaming SDK для Windows 8-приложений (http://visualstudiogallery.msdn.microsoft.com/04423d13-3b3e-4741-a01c-1ae29e84fea6?SRC=Home) (он имеет статус бета-версии, когда я это пишу), который призван помочь вам создавать мультимедиа-приложения с большим набором богатых возможностей, включая живое воспроизведение и защиту содержимого PlayReady. Я не описываю в данном курсе этот SDK, я лишь хочу, чтобы вы о нем знали.

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

Потоковая передача данных с сервера и DRM

Потоковая передача мультимедиа с сервера, это то, что вы уже делали, применяя элементы audio и video с URI, указывающими на удаленные ресурсы. Все это выполняется автоматически. На самом деле, все, что делает отличный мультимедиа-клиент – это общается с веб-сервисом, получает метаданные и списки элементов, помогает пользователю перемещаться по этой информации и, в конце концов, получает URI, который можно передать в атрибут src элемента audio или video. Затем, как только приложение получает событие canplay, вы можете вызвать метод play элемента для того, чтобы начать воспроизведение.

Конечно, мультимедийные записи часто защищены DRM, в противном случае содержимое платных сервисов не приносило бы денег владельцам прав! Таким образом, здесь нужен механизм для получения и проверки прав где-то между установкой атрибута src элемента и получением события canplay. К счастью, есть простые средства для того, чтобы это сделать:

Перед установкой атрибута src, создается экземпляр Windows.Media.Protection.MediaProtectionManager (http://msdn.microsoft.com/library/windows/apps/windows.media.protection.mediaprotectionmanager.aspx) и настраивается его свойство properties.

Прослушивается событие этого объекта serviceRequested, обработчик которого производит проверку прав и устанавливает флаг завершения, если все верно. (Два других события, о которых я просто хочу упомянуть, это componentloadfailed и rebootneeded.)

Присвоение средства управления защитой к элементу audio/video с использованием метода расширения msSetMediaProtectionManager (http://msdn.microsoft.com/library/windows/apps/hh465953.aspx).

Установка атрибута src. Это вызовет событие serviceRequested для начала обработки DRM, которая предотвращает вызов canplay до тех пор, пока проверка прав не завершится успешно.

Вы можете обратиться к материалам "Использование подключаемого DRM" (http://msdn.microsoft.com/library/windows/apps/hh452779.aspx), и "Обработка ошибок DRM" (http://msdn.microsoft.com/library/windows/apps/hh452767.aspx) для того, чтобы узнать подробности, здеь приведен минимальный гипотетический пример кода, который все это реализует:

var video1 = document.getElementById("video1");

video1.addEventListener('error', function () {
var error = video1.error.msExtendedCode;	
//...	
}, false);	

video1.addEventListener('canplay', function () {
video1.play();
}, false);

var cpm = new Windows.Media.Protection.MediaProtectionManager();	
cpm.addEventListener('servicerequested', enableContent, false); //Удалите это позже
video1.msSetContentProtectionManager(cpm);	
video1.src = "http://some.content.server.url/protected.wmv";


function enableContent(e) {
if (typeof (e.request) != 'undefined') {
var req = e.request;	
var system = req.protectionSystem;	
var type = req.type;	

//Предпринять необходимые действия на основе системы и типа
}
if (typeof (e.completion) != 'undefined') {
//Запрошенное действие завершено	
var comp = e.completion;	
comp.complete(true);	
}	
}	
 

Как конкретно вы проверяете права, зависит от сервиса, из которого вы получаете данные – и это не то, что вам захочется опубликовать!

Более полная демонстрация работы с DRM находится в примере "Простое использование PlayReady" (http://code.msdn.microsoft.com/windowsapps/Simple-PlayReady-sample-5c1aefaf), которому нужно, чтобы вы скачали и установили Microsoft PlayReady Client SDK (http://visualstudiogallery.msdn.microsoft.com/e02ccac7-f3eb-4b53-b11a-c657d5631483). PlayReady, если вы еще с ним не знакомы, это сервис лицензирования, который предоставляет Microsoft, таким образом, вам не нужно создавать что-то подобное с нуля. PlayReady Client SDK предоставляет дополнительные инструменты и подержку фреймворка для приложений, которые нуждаются в реализации онлайновых и оффлайновых сценариев работы с мультимедиа, таких, как прогрессивная загрузка, загрузка для владения, выдача напрокат и подписка. В дополнение к этому, с использованием этого SDK вам не нужно отправлять ваше приложение для тестирование на соответствие требованиям DRM. В любом случае, вот как пример использования PlayReady настр аивает свое средство защиты содержимого, просто для того, чтобы показать, как API WinRT используются с конкретными идентификаторами DRM-сервисов:

mediaProtectionManager = new Windows.Media.Protection.MediaProtectionManager();
mediaProtectionManager.properties["Windows.Media.Protection.MediaProtectionSystemId"] =
'{F4637010-03C3-42CD-B932-B48ADF3A6A54}'

var cpsystems = new Windows.Foundation.Collections.PropertySet();	
cpsystems["{F4637010-03C3-42CD-B932-B48ADF3A6A54}"] =	
"Microsoft.Media.PlayReadyClient.PlayReadyWinRTTrustedInput";	
mediaProtectionManager.properties[	
"Windows.Media.Protection.MediaProtectionSystemIdMapping"] = cpsystems;
 

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

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

Вот как такие приложения обычно работают:

  • Настройка необходимых каналов связи через сеть, это могут быть одноранговые системы, или системы с привлечением некоей централизованной службы.
  • Захват аудио и видео в поток с использованием API WinRT, которые мы уже видели (в особенности MediaCapture.startRecordToStreamAsync), или захват в пользовательский объект.
  • Выполнение любой дополнительной обработки данных в потоке. Обратите внимание, однако, что здесь применяются эффекты, подключенные к механизму захвата (MediaCapture.addEffectAsync), вместо тех, которые обрабатывают уже захваченные данные.
  • Кодирование потока для передачи любым необходимым способом.
  • Передача потока через сетевой канал связи.
  • Прием передач от других подключенных приложений.
  • Декодирование переданных приложению потоков и конверсия в большой двоичный объект (blob) с использованием MSApp.createBlobFromRandomAccessStream.
  • Использование URL.createObjectURL для подключения элементов audio и video к потоку.

Для того, чтобы увидеть это в действии, обратитесь к примеру "Коммуникация в реальном времени" (http://code.msdn.microsoft.com/Simple-Communication-Sample-eac73290), который реализует видеочат в Сценарии 2 и показывает работу с различными режимами задержки с Сценарии 1. Последние два шага в вышеприведенном списке так же показаны в примере "Приемник целевого объекта воспроизведения" (http://code.msdn.microsoft.com/windowsapps/PlayToReceiver-sample-607f00ed), который настроен на прием мультимедиа-потоков из других источников.

Целевые объекты воспроизведения

Последний вариант работы с потоковыми данными построен вокруг возможности передачи данных на целевые объекты воспроизведения (PlayTo), которая была представлена в Windows 7. Проще говоря, эта возможность представляет собой средство, с помощью которого приложения могут подключать локальное воспроизведение или просмотра элементов audio, video и img к удаленным устройствам.

Работа ведется с помощью API Windows.Media.PlayTo (http://msdn.microsoft.com/library/windows/apps/windows.media.playto.aspx) вместе с методами расширений, добавленных к медиа-элементам. Если, например, вы хотите запустить процесс передачи данных на целевой объект воспроизведения, непосредственно вызывая пользовательский интерфейс, выполните следующую последовательность действий:

  • Windows.Media.PlayTo.PlayToManager (http://msdn.microsoft.com/library/windows/apps/windows.media.playto.playtomanager.aspx ) :
    • getForCurrentView возвращает объект.
    • showPlayToUI запускает всплывающий элемент интерфейса, где пользователь выбирает приемник.
    • событие sourceRequested, когда пользователь выбирает приемник.
  • В sourceRequested
  • Принять событие медиа-элемента ended для воспроизведения дополнительных мультимедийных данных

Другой подход, как показано в примере "Проигрывание мультимедиа на целевых устройствах воспроизведения" (http://code.msdn.microsoft.com/windowsapps/Media-PlayTo-Sample-fedcb0f9), идет дальше и проигрывает мультимедийные файлы локально, затем позволяя пользователю выбрать целевое устройство воспроизведения из меню чудо-кнопки Устройства. В подобном случае вам не нужно ничего предпринимать, так как Windows возьмет текущий элемент, выполняющий воспроизведение, и соответствующим образом направит вывод. Но приложение может прослушивать событие statechanged объекта msPlayToSource.connection элемента (тип PlayConnection ( http://msdn.microsoft.com/library/windows/apps/windows.media.playto.playtoconnection.aspx ), которое будет вызвано, когда пользователь выберет целевое устройство и когда происходят другие изменения.

На самом деле, функция воспроизведения на целевом устройстве предназначена для передачи потоковых данных на медиа-проигрыватели, которые могут быть подключены к телевизору или к другим большим экранам. С помощью этого механизма вы можете выбрать локальное содержимое на устройстве, которое работает под управлением Windows 8 и отправить его прямо на проигрыватель, способный принимать потоковые данные. Но, кроме того, подобный приемник можно реализовать программно, то есть, создать приложение, которое может принимать потоковое содержимое из PlayTo-источника. В примере "Приемник PlayTo" (http://code.msdn.microsoft.com/windowsapps/PlayToReceiver-sample-607f00ed) реализован такой подход, и если вы запустите его на другом компьютере в вашей локальной сети, он будет показан в интерфейсе чудо-кнопки Устройства следующим образом:


Вы даже можете запустить это приложение с основного рабочего компьютера, воспользовавшись возможностями удаленной отладки Visual Studio, что позволит вам пошагово исполнить и код приложения-источника, и код приложения-приемника в одно и то же время! (Другая возможность – это запустить Windows Media Player на одном компьютере, установить параметр Разрешить удаленное управление проигрывателем (Allow Remote Control of My Player) в меню Поток (Stream). В результате данный компьютер появится в списке целевых устройств функции Воспроизвести на (PlayTo)).

Для того чтобы выполнять функции приемника, приложению обычно нужно объявить некоторые дополнительные сетевые возможности в манифесте, а именно - Интернет (клиент и сервер) (Internet (Client&Server)), и Частные сети (клиент и сервер) (Private Networks (Client&Server)), иначе приложение не будет работать так, как нужно. Затем приложение создает экземпляр Windows.Media.PlayTo.PlayToReceiver, как показано в функции startPlayToReceiver (js/audiovideoptr.js), в примере "Приемник PlayTo":

function startPlayToReceiver() {	
if (!g_receiver) {	
g_receiver = new Windows.Media.PlayTo.PlayToReceiver();
}	
 

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

var dmrVideo = id("dmrVideo");
dmrVideo.addEventListener("volumechange", g_elementHandler.volumechange, false); dmrVideo.addEventListener("ratechange", 
g_elementHandler.ratechange, false); dmrVideo.addEventListener("loadedmetadata", g_elementHandler.loadedmetadata, false); 
dmrVideo.addEventListener("durationchange", g_elementHandler.durationchange, false); dmrVideo.addEventListener("seeking", 
g_elementHandler.seeking, false); dmrVideo.addEventListener("seeked", g_elementHandler.seeked, false); dmrVideo.addEventListener
("playing", g_elementHandler.playing, false); dmrVideo.addEventListener("pause", g_elementHandler.pause, false); 
dmrVideo.addEventListener("ended", g_elementHandler.ended, false);
dmrVideo.addEventListener("error", g_elementHandler.error, false);
 

А так же – обработчики для событий, которые вызывает объект приемника:

g_receiver.addEventListener("playrequested", g_receiverHandler.playrequested, false); 
g_receiver.addEventListener("pauserequested", g_receiverHandler.pauserequested, false); 
g_receiver.addEventListener("sourcechangerequested", g_receiverHandler.sourcechangerequested, false); 
g_receiver.addEventListener("playbackratechangerequested", g_receiverHandler.playbackratechangerequested, false);
g_receiver.addEventListener("currenttimechangerequested", g_receiverHandler.currenttimechangerequested, false);
g_receiver.addEventListener("mutechangerequested",
g_receiverHandler.mutedchangerequested, false); g_receiver.addEventListener("volumechangerequested", 
g_receiverHandler.volumechangerequested, false); g_receiver.addEventListener("timeupdaterequested",
g_receiverHandler.timeupdaterequested, false); g_receiver.addEventListeer("stoprequested", 
g_receiverHandler.stoprequested, false); g_receiver.supportsVideo = true;
g_receiver.supportsAudio = true;
g_receiver.supportsImage = false;
g_receiver.friendlyName = 'SDK JS Sample PlayToReceiver';
 

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

// Анонсирует приемник в локальной сети и начинает прием команд
g_receiver.startAsync().then(function () {
g_receiverStarted = true;

// Предотвращает блокировку экрана	
if (!g_displayRequest) {	
g_displayRequest = new Windows.System.Display.DisplayRequest();
}	
g_displayRequest.requestActive();	
});	
 

Среди всех событий объекта-приемника, наиболее важное – sourcechanderequested, где eventArgs.stream содержит мультимедиа-данные, которые мы хотим проиграть в выбранном элементе. Это просто реализуется путем создания большого двоичного объекта из потока, и затем URI из этого объекта, которое мы можем присвоить атрибуту src элемента:

sourcechangerequested: function (eventIn) {
if (!eventIn.stream) {
id("dmrVideo").src = "";
} else {
var blob = MSApp.createBlobFromRandomAccessStream(eventIn.stream.contentType, eventIn.stream);
id("dmrVideo").src = URL.createObjectURL(blob, {oneTimeOnly: true});
}
}
 

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

Что мы только что изучили

  • Мультимедиа-элементы сожно создать в разметке или в коде, используя стандартные элементы img, svg, canvas, audio и video.
  • Три графических элемента – img, svg и canvas – могут выводить изображения, выглядящие одинаково, но обладающие разными характеристиками, касающиеся их создания и того, как они масштабируются. Все они, однако, могут быть стилизованы с помощью CSS.
  • Объект Windows.System.Display.DisplayRequest предназначен для отключения скринсейверов и экрана блокировки в течение проигрывания видео (или в других подходящих случаях).
  • И аудио- и видеоэлементы предоставляют множество расширений API (свойств, методов и событий) для работы с различными специфическими возможностями платформы Windows 8, таких, как горизонтальное отражение, масштабирование, оптимизация воспроизведения, 3D-видео, воспроизведение с низкой задержкой, воспроизведение на целевых устройствах, управление воспроизведением различных типов или категорий аудиозаписей, эффекты (обычно реализуемые в виде DLL в пакете приложения), и управление цифровыми правами.
  • Фоновое аудио поддерживается для различных категорий, для реализации этой возможности нужны объявления возможностей в манифесте, и обработчики для событий элементов управления воспроизведения (таким образом, звук может быть соответствующим образом воспроизводиться и приостанавливаться). События элементов управления мультимедиа так же важны для поддержки пользовательского интерфейса управления воспроизведением.
  • Посредством API WinRT приложения могут управлять богатым набором метаданных и свойств мультимедиа-файлов, в том числе – эскизами, изображениями альбомов и свойствами, специфичными для типа содержимого, в том числе, они имеют доступ к очень большому списку свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977%28v=vs.85%29.aspx).
  • API WinRT предоставляет средства для декодирования и кодирования мультимедиа-файлов и потоков, с помощью которых содержимое может быть конвертированы, могут быть изменены свойства содержимого. Это включает в себя поддержку пользовательских кодеков.
  • WinRT предоставляет богатое возможностями API для захвата мультимедиа (фотографий, видеоклипов, аудиозаписей) в том числе, встроенный пользовательский интерфейс для этих целей, вместе с возможностью реализовать собственный, а так же – возможности по перечислению имеющихся устройств и по доступу к ним.
  • Поддерживается воспроизведение потокового мультимедиа с сервера (с применением управления цифровыми правами, или без них, и с возможностью использовать PlayReady), между приложениями (как работа с входящими данными, так и с исходящими), и с приложений на целевые устройства воспроизведения (PlayTo). Приложение, кроме того, может быть настроено в качестве PlayTo-приемника.
< Лекция 5 || Лекция 6: 123456 || Лекция 7 >
Вадик Елетин
Вадик Елетин
Россия, г. Санкт-Петербург
Николай Жигульский
Николай Жигульский
Россия, Тверь, Тверской государственный технический университет