# Monday, June 08, 2009

France Télévisions – L’info en vidéo

Et une nouvelle version pour l’application L’info en vidéo.

Maintenant vous avez accès aux Directs !

ftvi-2 

Une nouvelle entrée “Evenements” dans le menu donne accès à tous les directs. Et lorsqu’une catégorie du menu contient un direct, un picto rouge vous l’indique.

ftvi-3

#    Comments [2] |

SLMedia et Smooth Streaming

Comme les français ont put le voir avec Roland Garros, le Smooth Streaming permet de diffuser des flux de grande qualité qui vont s’adapter à la connexion et à la puissance de la machine et de pouvoir faire du timeshifting (contrôle du direct) sur les emissions live.

Smooth Streaming c’est quoi ?

Le smooth streaming n’est pas un format de compression de video. C’est une technologie de diffusion qui permet de découper la vidéo et le son en morceaux de 2 secondes et diffuser le tout par http. La vidéo étant encodé en plusieurs niveau de qualité, nous obtenons des échantillons de différents poids qui vont être mis à disposition sur un serveur web.
La partie client web (silverlight) va récupérer ces différents paquets et les mettre bout à bout pour reconstituer le flux vidéo. L’application silverlight récupérera le paquet de poids correspondant au mieux à la qualité de la connexion à internet.
Pour la partie diffusion en live, un ou plusieurs encodeur envoyent au serveur web ces paquets de 2 secondes au fur et à mesure qu’ils sont reçu de la source et encodés.
Pour silverlight 2, la vidéo est au format VLC1 et nous devrions avoir droit au H264 avec silverlight 3.
Le découpage en paquets et la diffusion au format HTTP permettent de tirer partie des différents Cache HTTP qui existent sur internet.

Côté serveur

La diffusion des flux smooth streaming nécessitent des composants côté serveur. Actuellement, IIS7 est la seule plateforme supportant la diffusion de ce format. Deux versions existent. La première vous permet de diffuser des vidéos préenregistrées au format smooth streaming et la deuxième encore en beta permet la diffusion de flux live.

Côté client

Silverlight est actuellement le seul moyen de lire de la vidéo en Smooth Streaming. Des exemples existent pour Silverlight 2 et Silverlight 3.

Encodeur

Pour encoder des vidéos préenregistrées, vous devrez passer par Microsoft Expression Encoder SP1. Pour les flux live, des encodeurs hardwares sont en cours de développement. Pour Roland Garros, c’est la société Inlet qui les a fourni. Vous pouvez cependant simuler un flux live à partir d’une vidéo préencodée en Smooth Streaming. Allez sur le site officiel et téléchargez le starter kit. Vous trouverez 2 exécutables PushEncoder32.exe et PushEncoder64.exe qui poussent votre vidéo préencodée sur le point de distribution live.

SLMedia

La librairie de décodage du flux smoothstreaming (Microsoft.Web.Media.SmoothStreaming.dll) est récupérable dans le player d’exemple silverlight du starter kit.

Pour cet exemple, je vais réutiliser le VideoPlayer d’un précédent billet.
L’assignation d’une vidéo à un MediaElement ne se fait pas de la même manière que la video soit du smooth streaming ou non. Pour gérer ceci, la notion de VideoSourceAdapter et VideoAdapter a été ajoutée à SLExtensions. Le VideoSourceAdapter va instancier la bonne source en fonction de l’url de la vidéo. La première chose à faire dans le projet est de référencer le projet SLMedia.SmoothStreaming et d’initialiser le SmoothStreamingVideoSourceAdapter. Il suffit de rajouter la ligne ci-dessous au constructeur de la classe App.xaml.cs.

            SLMedia.SmoothStreaming.SmoothStreamingVideoSourceAdapter.Initialize();

Ensuite, changez le binding sur le source du MediaElement et l’url de la video.

        <MediaElement x:Name="mediaelement"

                    slvideo:VideoSourceAdapter.Source="{Binding Path=CurrentItem.SourceUri}"

                    slvideo:VideoController.MediaElement="{StaticResource controller}"

                    IsMuted="{Binding Path=IsMuted}"

                    Volume="{Binding Path=Volume}"

                    AutoPlay="{Binding Path=AutoPlay}"   

                    />

 

 

            controller.Playlist.Add("http://localhost/live.isml/Manifest");

Attention, le chemin d’accès au Manifest est sensible au crossdomain. Pensez à autoriser votre player à accéder à la video si le player n’est pas dans le même domaine (crossdomain.xml)

Poussez votre video en live  PushEncoder64.exe http://localhost/live.isml "Big Buck Bunny.ism" et lancez votre player. Vous devriez voir la video. Si vous voulez un contenu préencodé, téléchargez la video Big Buck Bunny ici.

Par défaut, la lecture du flux commence toujours au début de la vidéo qui a été encodée. Si vous voulez rejoindre le direct, vous pouvez appeler la fonction GoToLive du VideoAdapter ou créer un mediaitem de type LiveVideoItem et lui assigner sa propriété JoinLive.

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            controller.Playlist.Add(new LiveVideoItem

            {

                Source = "http://localhost/live.isml/Manifest",

                JoinLive = true

            });

            controller.Next();

        }


la timeline pour le Live Smooth Streaming

Pour les événements live, les informations de position ne démarrent pas forcément à 0. Il faut changer la déclaration des bindings du slider pour tenir compte des propriétés Start et LivePosition.

            <slec:Slider Maximum="{Binding Path=VideoAdapter.LivePosition, Converter={StaticResource timeSpanConverter}}"

                        Minimum="{Binding Path=VideoAdapter.Start, Converter={StaticResource timeSpanConverter}}"

                        MoveValue="{Binding Converter={StaticResource timeSpanConverter}, Mode=TwoWay, Path=Position}"

                        Width="200" Margin="20,0,0,0"

                        />

Quelle représentation pour la timeline

  1. Un slider simple

Ce contrôle est utilisé dans le majorité des players vidéos disponible sur internet. Il se prête bien pour des vidéos de taille connues et relativement petites. Dans le cas de diffusion de flux live, la taille du slider ne représente pas toujours la même durée. Au bout d’une heure d’émission, amener le slider au milieu reculera d’une demi heure alors qu’au bout d’une journée on reculera d’une demi journée.

image

  1. Un “slider inversé”

Le marqueur au milieu indique la position de lecture. La barre orange indique la durée de la vidéo. Cette barre grandit au fur et à mesure que le flux live est émis. Quand l’utilisateur regarde en live, la barre orange s’agrandit vers la gauche et rien ne dépasse à droite du marqueur.
Si l’utilisateur met en pause, le barre s’agrandit à droite du marqueur montrant qu’on est plus en live et indique la durée du décalage par rapport au live.
Quand la lecture reprend, la barre regrandit à gauche.

Contrairement au slider simple, ce type de contrôle permet d’avoir une échelle de temps constante tout au long de la diffusion. Lorsqu’on déplace la timeline, c’est la barre orange qui se déplace, le marqueur reste toujours au milieu. Peut être un peu déroutant au départ, un utilisateur en comprendra vite la logique

image

  1. Un slider sur une ligne de temps

C’est ce qui a été utilisé pour Roland Garros, une barre de temps représente la journée entière. La taille du slider grandit au fur et à mesure du live. Le slider garde une échelle constante mais est quasi invisible au départ. Le principe de déplacement du curseur est préservé.

image

N’oubliez pas de télécharger les sources de SLMedia sur le site de slextensions.

#    Comments [0] |

SLMedia le player Photo / Video de SLExtensions

Les librairies SLMedia regroupent tout ce qu'il vous faut pour gérer vos galeries photos et vidéo. Ces librairies sont séparées en plusieurs dlls gérant chacune un type de média.

  • SLMedia.Core : Librairie centrale prenant en charge les fonctions communes.
  • SLMedia.Picture : Librairie vous permettant de réaliser des slideshows d’images.
  • SLMedia.Deepzoom : Librairie vous permettant d’afficher des galeries deepzoom de vos images.
  • SLMedia.Video : Librairie gérant les galeries vidéos.
  • SLMedia.SmoothStreaming : Gestion des vidéos en Smooth Streaming

Création d’un player video avec SLMedia

La réalisation d’un player avec SLMedia repose sur les concepts de Binding et de Behavior. Les Bindings vont vous servir à lier les informations provenant du controller (ici un VideoController) et les différents éléments graphiques qui vont vous permettre d’afficher et d’agir sur votre vidéo.

MediaController

Cette classe appartenant à SLMedia.Core sert de base au VideoController. Elle regroupe les fonctionnalités communes aux différents controllers.

  • Gestion de la playlist (Next, Previous, IsPlaying, SelectedItem)
  • Gestion du fullscreen (IsFullscreen)
  • Gestion des progressions pour les slideshow / videos (Position, Duration)
  • Etc..

VideoController

Cette classe hérite du MediaController et lui rajoute des fonctions spécifiques pour la vidéo.

  • MediaElement
  • Buffering
  • Support de différentes source par les VideoAdapter

Etape 1 : Affichage d’une video de la playlist

Dans votre page xaml, référencez le namespace correspondant à SLMedia.Video et ajouter le VideoController aux ressources.

<UserControl x:Class="VideoPlayer1.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:slvideo="clr-namespace:SLMedia.Video;assembly=SLMedia.Video"

   >

    <UserControl.Resources>

        <slvideo:VideoController x:Name="controller" />

    </UserControl.Resources>

Ensuite posez un MediaElement et associez sa source avec la propriété CurrentItem de notre controller. Le CurrentItem sera du type IMediaItem et possèdera donc une propriété SourceUri contenant l’url de la vidéo à afficher.

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource controller}}" >

        <MediaElement x:Name="mediaelement"

                    Source="{Binding Path=CurrentItem.SourceUri}"

                    />

    </Grid>

Il ne reste plus qu’à renseigner un nouvel item dans la playlist et de le sélectionner pour que la video se lancer.

using SLMedia.Video;

using SLMedia.Core;

 

namespace VideoPlayer1

{

    public partial class Page : UserControl

    {

        public Page()

        {

            InitializeComponent();

            controller = (VideoController)Resources["controller"];

 

            this.Loaded += new RoutedEventHandler(Page_Loaded);

        }

 

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            controller.Playlist.Add("http://labs.ucaya.com/lake.wmv");

            controller.Next();

        }

    }

}

Pour rendre complétement opérationnel notre videocontroller, nous devons lui indiquer quel est le MediaElement qui affiche la vidéo. De cette manière il pourra récupérer les états de lecture, de progression et de buffering. Nous allons également lier quelques propriétés supplémentaires qui nous permettrons de tout contrôler depuis le VideoController.

        <MediaElement x:Name="mediaelement"

                    Source="{Binding Path=CurrentItem.SourceUri}"

                    slvideo:VideoController.MediaElement="{StaticResource controller}"

                    IsMuted="{Binding Path=IsMuted}"

                    Volume="{Binding Path=Volume}"

                    AutoPlay="{Binding Path=AutoPlay}"   

                    />

Etape 2 : Lecture / Pause

L’état lecture / pause est géré dans notre controller par la propriété IsPlaying. Un binding entre une checkbox et cette propriété permetra de contrôler facilement l’état de lecture.

        <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Background="#50000000" Margin="30">

            <CheckBox IsChecked="{Binding Path=IsPlaying, Mode=TwoWay}" />

        </StackPanel>

Etape 3 : Position / Durée

Un slider Bindé sur les propriétés Duration et Position fera l’affaire. Les propriétés Duration et Position étant du type TimeSpan, nous allons utiliser un IValueConverter pour transformer la valeur en Double.

<UserControl x:Class="VideoPlayer1.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:slvideo="clr-namespace:SLMedia.Video;assembly=SLMedia.Video"

   xmlns:slec="clr-namespace:SLExtensions.Controls;assembly=SLExtensions.Controls"

   xmlns:sled="clr-namespace:SLExtensions.Data;assembly=SLExtensions.Data"

   Foreground="White"

    >

    <UserControl.Resources>

        <slvideo:VideoController x:Name="controller" />

        <sled:TimeSpanConverter x:Name="timeSpanConverter"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource controller}}">

        <MediaElement x:Name="mediaelement"

                    Source="{Binding Path=CurrentItem.SourceUri}"

                    slvideo:VideoController.MediaElement="{StaticResource controller}"

                    IsMuted="{Binding Path=IsMuted}"

                    Volume="{Binding Path=Volume}"

                    AutoPlay="{Binding Path=AutoPlay}"   

                    />

        <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Background="#50000000" Margin="30">

            <CheckBox IsChecked="{Binding Path=IsPlaying, Mode=TwoWay}" />

            <slec:Slider Maximum="{Binding Converter={StaticResource timeSpanConverter}, Path=Duration}"

                        MoveValue="{Binding Converter={StaticResource timeSpanConverter}, Mode=TwoWay, Path=Position}"

                        Width="200" Margin="20,0,0,0"

                        />

            <TextBlock Text="{Binding Converter={StaticResource timeSpanConverter}, Path=Position}"

                    Margin="20,0,0,0"/>

            <TextBlock Text=" / " />

            <TextBlock Text="{Binding Converter={StaticResource timeSpanConverter}, Path=Duration}" />

        </StackPanel>

    </Grid>

</UserControl>

Si vous utilisez le slider de base de silverlight, vous noterez des problèmes lorsque vous déplacez le curseur. Pendant que vous déplacez le curseur, la propriété Value peut être remise à jour par le binding et le curseur donne l’impression de sauter.

Etape 4 : Volume

De même que pour la position, nous allons utiliser un slider pour le volume et une checkbox pour le mute

            <CheckBox IsChecked="{Binding Path=IsMuted, Mode=TwoWay}" Margin="20,0,0,0"/>

            <Slider Maximum="1" SmallChange="0.1" LargeChange="0.1"

                   Value="{Binding Path=Volume, Mode=TwoWay}" Width="50" />

Etape 5 : Buffering - Downloading

Encore du binding

            <TextBlock Text="Buffering:" />

            <TextBlock Text="{Binding Path=BufferingProgress, Mode=TwoWay, Converter={StaticResource strConverter}, ConverterParameter='{0:p}'}" />

            <Slider Maximum="1"

                   Value="{Binding Path=BufferingProgress, Mode=TwoWay}" Width="50" IsHitTestVisible="False" Margin="5,0,0,0"/>

 

            <TextBlock Text="Downloading:" Margin="20,0,0,0"/>

            <TextBlock Text="{Binding Path=DownloadProgress, Mode=TwoWay, Converter={StaticResource strConverter}, ConverterParameter='{0:p}'}" />

            <Slider Maximum="1"

                   Value="{Binding Path=DownloadProgress, Mode=TwoWay}" Width="50" IsHitTestVisible="False"

                   Margin="5,0,0,0"/>

Etape 6 : Gestion des états visuels

Le VideoController centralise les propriétés de notre player video. Il est possible de changer l’état visuel de nos contrôles en fonction des propriétés du VideoController. Nous allons utiliser le behaviors fournis par SLExtensions pour mapper ces propriétés à nos VisualStates.

<UserControl x:Class="VideoPlayer1.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:slvideo="clr-namespace:SLMedia.Video;assembly=SLMedia.Video"

   xmlns:slec="clr-namespace:SLExtensions.Controls;assembly=SLExtensions.Controls"

   xmlns:sled="clr-namespace:SLExtensions.Data;assembly=SLExtensions.Data"

 

   xmlns:inter="clr-namespace:Microsoft.Expression.Interactivity;assembly=Microsoft.Expression.Interactivity"

   xmlns:slint="clr-namespace:SLExtensions.Interactivity;assembly=SLExtensions.Interactivity"

 

   xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"

 

   Foreground="White"

    >

    <UserControl.Resources>

        <slvideo:VideoController x:Name="controller" />

        <sled:TimeSpanConverter x:Name="timeSpanConverter"/>

        <sled:StringFormatConverter x:Name="strConverter"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource controller}}">

        <vsm:VisualStateManager.VisualStateGroups>

            <vsm:VisualStateGroup x:Name="PlayingStates">

                <vsm:VisualStateGroup.Transitions>

                    <vsm:VisualTransition GeneratedDuration="00:00:00.3000000"/>

                </vsm:VisualStateGroup.Transitions>

                <vsm:VisualState x:Name="Playing">

                    <Storyboard>

                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="stackPanel" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">

                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#5039FF00"/>

                        </ColorAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

                <vsm:VisualState x:Name="Paused">

                    <Storyboard>

                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="stackPanel" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">

                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#50D56700"/>

                        </ColorAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

            </vsm:VisualStateGroup>

        </vsm:VisualStateManager.VisualStateGroups>

        <inter:Interaction.Behaviors>

            <slint:MapState Source="{StaticResource controller}" Property="IsPlaying" >

                <slint:MapStateMapping StateName="Playing" Value="true"/>

                <slint:MapStateMapping StateName="Paused" Value="false"/>

            </slint:MapState>

        </inter:Interaction.Behaviors>

 

        <MediaElement x:Name="mediaelement"

                    Source="{Binding Path=CurrentItem.SourceUri}"

                    slvideo:VideoController.MediaElement="{StaticResource controller}"

                    IsMuted="{Binding Path=IsMuted}"

                    Volume="{Binding Path=Volume}"

                    AutoPlay="{Binding Path=AutoPlay}"   

                    />

        <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Background="#50000000" Margin="30" x:Name="stackPanel">

            <CheckBox IsChecked="{Binding Path=IsPlaying, Mode=TwoWay}" />

            <slec:Slider Maximum="{Binding Converter={StaticResource timeSpanConverter}, Path=Duration}"

                        MoveValue="{Binding Converter={StaticResource timeSpanConverter}, Mode=TwoWay, Path=Position}"

                        Width="200" Margin="20,0,0,0"

                        />

            <TextBlock Text="{Binding Converter={StaticResource timeSpanConverter}, Path=Position}"

                    Margin="20,0,0,0"/>

            <TextBlock Text=" / " />

            <TextBlock Text="{Binding Converter={StaticResource timeSpanConverter}, Path=Duration}" />

 

            <CheckBox IsChecked="{Binding Path=IsMuted, Mode=TwoWay}" Margin="20,0,0,0"/>

            <Slider Maximum="1" SmallChange="0.1" LargeChange="0.1"

                   Value="{Binding Path=Volume, Mode=TwoWay}" Width="50" />

 

            <TextBlock Text="Buffering:" />

            <TextBlock Text="{Binding Path=BufferingProgress, Mode=TwoWay, Converter={StaticResource strConverter}, ConverterParameter='{0:p}'}" />

            <Slider Maximum="1"

                   Value="{Binding Path=BufferingProgress, Mode=TwoWay}" Width="50" IsHitTestVisible="False" Margin="5,0,0,0"/>

 

            <TextBlock Text="Downloading:" Margin="20,0,0,0"/>

            <TextBlock Text="{Binding Path=DownloadProgress, Mode=TwoWay, Converter={StaticResource strConverter}, ConverterParameter='{0:p}'}" />

            <Slider Maximum="1"

                   Value="{Binding Path=DownloadProgress, Mode=TwoWay}" Width="50" IsHitTestVisible="False"

                   Margin="5,0,0,0"/>

 

            <CheckBox IsChecked="{Binding Path=IsFullscreen, Mode=TwoWay}" Margin="20,0,0,0" Content="Fullscreen" Foreground="White"/>

 

        </StackPanel>

    </Grid>

</UserControl>

#    Comments [0] |