Мультимедиа, рукописный ввод и Deep Zoom
Управление положением курсора воспроизведения
Для управления текущим положением курсора воспроизведения используются свойства NaturalDuration (Номинальная продолжительность) и Position (Положение) элемента мультимедиа. После того, как свойство CurrentState устанавливается в значение Opened, становится возможным получение значения и свойства NaturalDuration. Продолжительность видео в секундах можно получить с помощью Natu-ralDuration.Seconds и потом преобразовать это значение в часы, минуты и секунды.
В этом примере событие CurrentStateChanged элемента управления MediaElement ассоциировано с функцией doState (из предыдущего примера). Однако теперь эта функция перехватывает значение свойства NaturalDuration. В JavaScript-версии используется вспомогательная функция convertDT для преобразования возвращаемого значения в строку. Рассмотрим код на JavaScript:
function doState(sender, args) { var meVid = sender.findName("vid"); var txtStat = sender.findName("txtStat"); var datetime = new Date(0, 0, 0, 0, 0, meVid.naturalDuration.Seconds) durationString = convertDT(datetime); txtStat.Text = durationString.toString(); } function convertDT(datetime) { var hours = datetime.getHours(); var minutes = datetime.getMinutes(); var seconds = datetime.getSeconds(); if (seconds < 10) { seconds = "0" + seconds; } if (minutes < 10) { minutes = "0" + minutes; } var durationString; if (hours > 0) { durationString = hours.toString() + ":" + minutes + ":" + seconds; } else { durationString = minutes + ":" + seconds; } return durationString; }
Далее следует замечательный пример того, как .NET Framework в Silverlight 2 существенно упрощает разработку: все это может быть реализовано одной строкой кода на C#:
private void doState(object sender, RoutedEventArgs e) { txtStat.Text = vid.NaturalDuration.ToString(); }
Вот XAML, В котором используется представленная выше функция:
<Canvas x:Name="sample9" Opacity="1"> <MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width="200" Stretch = "Fill" CurrentStateChanged="doState" BufferingTime="0:0:10" /> <TextBlock x:Name="txtStat"> </TextBlock> </Canvas>
Получить текущее положение курсора воспроизведения можно с помощью свойства Position. В этом примере позиция выводится в текстовом блоке при приостановке воспроизведения (Для тестирования можете оставить в XAML-коде три "кнопки" Play, Stop и Pause и соответствующие им обработчики событий doPlay и doStop с предыдущего примера, но закомментировать тело функции doState ). Необходимый код на JavaScript для функции doPause выглядел бы примерно так:
function doPause(sender, args) { var meVid = sender.findName("vid"); meVid.Pause(); var txtStat = sender.findName("txtStat"); var datetime = new Date(0,0,0,0,0, meVid.Position.Seconds); positionString = convertDT(datetime); txtStat.Text = positionString.toString(); }
И, как и ранее, эквивалентный код на C# намного проще:
private void doPause(object sender, MouseButtonEventArgs e) { vid.Pause(); txtStat.Text = vid.Position.ToString(); }
Использование маркеров временной шкалы мультимедиа
Маркер временной шкалы - это элемент метаданных, ассоциированный с конкретной точкой на временной шкале мультимедиа. Обычно эти маркеры создаются и кодируются в мультимедиа заранее с помощью такого ПО, как Expression Encoder, и часто применяются для установления в видео поисковых меток.
Silverlight поддерживает эти маркеры и формирует событие MarkerReached (Маркер достигнут) при встрече с маркером в ходе воспроизведения. Это событие можно перехватывать и использовать как триггер для действий, которые должны выполняться при достижении данной отметки.
Далее представлен фрагмент XAML, в котором с помощью атрибута MarkerReached задается обработчик события встречи с маркером, JavaScript-функция handleMarker:
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width = "200" MarkerReached = "handleMarker" />
Среди аргументов данного события имеется объект marker (маркер). Он содержит объект TimeSpan (Диапазон времени) с меткой времени, в которой установлен маркер. В предыдущем разделе, "Управление положением курсора воспроизведения", представлен пример преобразования объекта Time-Span в формат, удобный для восприятия пользователем. Также marker содержит свойство Type (Тип).
Его значением является строка, которую задает человек, кодирующий видео. Наконец, имеется параметр Text, допускающий в качестве своего значения текст в свободном формате и обычно используемый для описания параметра. Далее представлен JavaScript-код для чтения всех трех параметров и создания строки, отображаемой в окне уведомления:
function handleMarker(sender, args) { var strMarkerStatus = args.marker.time.seconds.toString(); strMarkerStatus += " : "; strMarkerStatus += args.marker.type; strMarkerStatus += " : "; strMarkerStatus += args.marker.text; alert(strMarkerStatus); }
Код на C# очень похож на предыдущий; заметьте, что args типа TimeLineMarkerRoutedEventArgs:
private void handleMarker(object sender, TimelineMarkerRoutedEventArgs e) { string strMarkerStatus = e.Marker.Time.ToString(); strMarkerStatus += " : "; strMarkerStatus += e.Marker.Type; strMarkerStatus += " : "; strMarkerStatus += e.Marker.Text; }
Как это выглядит, можно увидеть на рис. 11.11.
Маркеры временной шкалы можно добавлять в медиафайл также динамически, используя код на Silverlight. При этом поисковые метки можно задавать через процентное соотношение положения метки к общей продолжительности файла, например.
Далее представлен пример, в котором XAML для MediaElement определяет функцию handleOpen (Обработка открытия), выполняющуюся при открытии файла мультимедиа. Она вставляет новый объект временной шкалы в видео на 10-секундной отметке. Этот элемент не сохраняется в видео постоянно, только до завершения сеанса.
<MediaElement x:Name="vid" Source="balls.wmv" Height="200" Width = "200" MarkerReached = "handleMarker" MediaOpened= "handleOpened" />
Обработчик должен создать новый элемент временной шкалы в XAML и добавить его в коллекцию маркеров MediaElement. В данном случае, задается маркер временной шкалы на отметке 10 секунд, для которого Type определен как 'My Temp Marker' (мой временный маркер) и Text- 'Dynamically Added Marker' (Динамически добавляемый маркер).
Вот как это выглядело бы в JavaScript:
function handleOpened(sender, args) { var marker = sender.getHost().content.createFromXam l( "<TimelineMarker Time='0:0:10'" + " Type='My Temp Marker' Text='Dynamically Added Marker' />"); sender. markers.add(marker); }
И вот аналогичный код в .NET:
private void handleOpened(object sender, RoutedEventArgs e) { TimelineMarker t = new TimelineMarker(); t.Time = new TimeSpan(0, 0, 0, 10); t.Type = "My Temp Marker"; t.Text = "Dynamically Added Marker"; vid.Markers.Add(t); }
Коллекцию маркеров MediaElement составляют объекты TimeLineMarker (Маркер временной шкалы), поэтому для введения нового маркера просто создается новый объект TimeLineMarker, задаются его свойства Time, Type и Text, и этот объект добавляется в коллекцию. Silverlight имеет достаточно развитую логику и знает, когда должно быть сформировано событие, исходя из заданного Time, поэтому при создании новых маркеров нет необходимости добавлять их в порядке расположения на временной шкале.
Теперь, когда MediaElement достигает 10-секундной отметки при воспроизведении, появляется диалоговое окно уведомления, как показано на рис. 11.12.
Закрашивание поверхностей видеоизображением с помощью VideoBrush
Особенно замечательная возможность Silverlight - использование видео для заливки поверхности с помощью VideoBrush. Сделать это очень просто. Во-первых, необходим элемент мультимедиа, который загрузит видео. Он должен быть скрыт и не должен принимать события мыши. Для этого его прозрачность задается равной 0 и свойству IsHitTestVisible (Объект виден для механизма обработки кликов) присваивается значение false. Также элементу мультимедиа должно быть задано имя посредством свойства x:Name. Рассмотрим пример:
<MediaElement x:Name="vid" Source="balls.wmv" Opacity="0" IsHitTestVisible="False" />
Теперь объект VideoBrush можно применять к любому объекту точно так же, как любую другую кисть. В качестве источника кисти задается MediaElement (вот почему ему обязательно должно быть присвоено имя). Также можно задать свойство Stretch для управления визуальными эффектами кисти.
Например, здесь представлен TextBlock, для закрашивания Foreground которого используется Video-Brush:
<TextBlock FontFamily="Verdana" FontSize="80" FontWeight="Bold" TextWrapping = "Wrap" Text="Video"> <TextBlock.Foreground > <VideoBrush SourceName="vid"/> </TextBlock.Foreground > </TextBlock>
Silverlight теперь будет формировать визуальное представление текста, используя VideoBrush. На рис. 11.13 показано, как это будет выглядеть.