Le point sur NetStream.close(), le bug Video.smoothing/ Video.clear() et la classe VideoDisplay de LowRA

Je vais aborder dans cet article une problématique assez récurrente en matière de gestion video en Flash. Les classes concernées sont les classes as3 natives NetStream et Video. Je profiterai de l’ occasion pour vous montrer comment gérer simplement la Vidéo avec la classe VideoDisplay de LowRA (dans son implémentation actuelle).

Fermer un flux NetStream et arrêter le téléchargement

Ce paragraphe ne traite pas d’un bug mais s’ attache à vous exposer comment bien utiliser la classe NetStream. 2 cas de figure peuvent se présenter:

1) J’ appel un média et décide de fermer le flux presque immédiatement. Horreur, Je constate que le média continue de se télécharger !

2) Je souhaite réutiliser une instance NetStream et appeler un nouveau média sur celui-ci. Horreur, Je constate que le premier média continue parfois de se télécharger (a priori plateforme Windows uniquement).

Gérer la vidéo avec une instance NetStream unique peut être un choix intéréssant si vous êtes en recherche de performance optimale. En effet, la consommation mémoire s’avère être au plus bas et stable dans des conditions de stress tests.

Ceci étant le coût d’ utilisation d’une instance NetStream dédiée (une instance pour chaque nouvel appel vers un média) reste minime dans des conditions d’utilisation classique. Il s’agit de l’implémentation retenue le plus couramment:

- Akamai Multi Player‘s VideoController class

[as]
// Handles a successful connection
private function connectedHandler():void {
if (!_ak || !_ak.netConnection) {
return;
}

_successfulPort = _ak.actualPort;
_successfulProtocol = _ak.actualProtocol;
_model.debug(“Connected to ” + _ak.netConnection.uri);
_model.isLive = _ak.isLive;
_ns = new AkamaiDynamicNetStream(_ak);
[/as]

- LowRA’s VideoDisplay class
[as]
protected function _load() : void
{
if( DEBUG ) PixlibDebug.DEBUG( this + “._load” );
if ( !getURL() )
{
PixlibDebug.ERROR( this + ” can’t play without any valid url property, loading fails.” );
} else {
_bLoadProblem = false;
_connection = new NetConnection();
_connection.connect( null );
_stream = new NetStream( _connection );
[/as]

Les exemples qui suivent se baseront sur le choix d’une attribution NetStream  systématique (un nouveau flux pour chaque appel média), non parce que le choix d’ une instance NetStream unique soit moins fiable mais parce qu’ il impose une contrainte ergonomique (interdire toute nouvelle ouverture de flux tant que le média en cours de lecture n’est pas assuré d’ être correctement fermé).

S’assurer de la fermeture d’un flux video

C’est assez simple en réalité. Pour bien contrôler un objet NetStream il faut respecter le modèle évenementielle. On ecoutera pour ce faire l’évenement NetStatusEvent, en attente du code Play.Start:

[as]
_stream.addEventListener(NetStatusEvent.NET_STATUS, _onNetStatus);
_stream.play( “http://www.deja-vue.net/test/mp4/juno.mp4″ );

private function _onNetStatus ( e : NetStatusEvent ) : void
{
switch ( e.info.code )
{
case ‘NetStream.Play.Start’ :
_stream.close();
break;
}
}[/as]

On comprendra dès lors que la gestion de la vidéo devient vite compliquée en passant par la manipulation de l’api native puisqu’il faut prendre en charge des callbacks sur chaque nouvelle instance NetStream.

D’ où l’intérêt de passer par un gestionnaire comme la classe VideoDisplay de LowRA précisemment dédiée à cette tache. Son utilisation est assez simple:

[as]
import com.bourre.media.video.VideoDisplay;
import com.bourre.media.video.VideoDisplayEvent;

var _video : VideoDisplay = new VideoDisplay();
addChild(_video.getVideo());

_video.addEventListener(VideoDisplayEvent.onStartStreamEVENT, _onStartStream);
_video.load(new URLRequest(“http://www.deja-vue.net/test/mp4/juno.mp4″));

public function _onStartStream (e : VideoDisplayEvent):void {}
[/as]

A l’ heure ou je publie cet article la classe VideoDisplay ne résout toutefois pas encore la problématique précedemment exposée.

Nul doute que l’ équipe se chargera d’ améliorer l’ implémentation au plus tôt. En attendant je vous propose une solution articulée autour de l’ héritage permettant:
-  d’ appeler un nouveau média avec fermeture automatique du flux existant et du téléchargement en cours.
-  de fermer un flux et d’ arrêter le téléchargement en cours.

En voici l’ utilisation :

[as]
import com.bourre.commands.CommandManagerMS;
import com.bourre.commands.Delegate;
import com.bourre.media.video.VideoDisplayEvent;

var vd : VideoDisplayExtended = new VideoDisplayExtended(this/*DisplayObjectContainer*/);
vd.addVideo();
vd.addEventListener(VideoDisplayEvent.onStartStreamEVENT, _onStartStream);

// tests
vd.load( new URLRequest(_sURL1) );
vd.load( new URLRequest(_sURL2) );
CommandManagerMS.getInstance().delay(new Delegate(vd.load, new URLRequest(_sURL1)), 3000);
CommandManagerMS.getInstance().delay(new Delegate(vd.closeStream), 6000);
[/as]

Voici un exemple avec les sources

VideoDisplayExtended.as (226)
VideoDisplayTest.zip (251)

Une autre problématique qui revient assez souvent, et pour cause il s’ agit cette fois-ci d’ un problème qui à la peau dure , le vidage d’ un objet Video.

Vidage d’ un objet Video avec Video.clear()

Quand je parle d’ un problème qui à la peau dure, je ne plaisante malheureusement pas comme certains d’entre vous le savent sans doute déjà car sa notification (ASC-3115, FP-539, FP-178) remonte maintenant à environ un an et reste toujours d’ actualité. D’après les ingénieurs en charge de sa résolution, un fix serait prévue seulement pour la prochaine mise à jour majeure du player !

Nous en sommes à la version 10.0.22.87 et rien de nouveau sous le capot…

Mais attachons nous plutôt à l’origine du problème. Video.clear() nous indique un comportement anormal mais n’en est pas la source. Video.smoothing est le véritable levier introduisant le bug.

Dès lors que la propriété smoothing voit sa valeur de départ changé (valeur booléenne positive) la méthode Video.clear() devient inefficace.  Et non seulement Video.clear() échoue mais NetStream.seek() devient lui aussi inopérant sous ces mêmes conditions (vous constaterez en effet qu’un appel seek(0) ne parvient pas à nettoyer l’objet video).

Les deux tests suivants présentent des résultats assez surprenant:

[as]
var _video : Video = new Video();

_video.smoothing = true;
trace(“_video.smoothing:” + _video.smoothing);//true

_video = new Video();
trace(“_video.smoothing:” + _video.smoothing);//true ???[/as]

Pas mal non ?

Et que penser de ceci ?

[as]
var _video1 : Video = new Video();
var _video2 : Video = new Video();
_video1.smoothing = true;

trace(“_video2.smoothing:” + _video2.smoothing);//true ???
[/as]

Workarounds

Il a été suggéré de restaurer la propriété smoothing sur sa valeur initiale (FP-178):

Peut-être ceci a t-il pu fonctionner sous certaines versions antérieures du player mais cela ne marche à priori pas avec les players les plus récents (10.0.12.36 et  10.0.22.87). Si vous êtes plus chanceux vous êtes plus qu’ invité à vous manifester ☺ !
Il nous reste heureusement une alternative, un peu radicale, certes (mais la seule) consistant à détruire et recréer un nouvel objet Video. Voici l’implémentation de cette technique extrait de la classe VideoDisplayExtended précédemment évoquée.

[as]
// VideoDisplayExtended.as
public function removeVideo():void
{
if( _target.contains(_video) ) _target.removeChild(_video);
}

public function addVideo():void
{
if( !_target.contains(_video) ) _target.addChild(_video);
}

public function setVideo(v:Video):void
{
if(_video) _video.attachNetStream(null);
_video = null;
_video = v;
_video.attachNetStream(_stream);
}
[/as]

[as]
// basicplayer.fla
function _onStopStream(e : VideoDisplayEvent) : void
{
// …
if(vd.getVideo().smoothing) {
vd.removeVideo()
vd.setVideo(new Video());
// update position
_onMetaData(null);
vd.addVideo()
} else {
vd.getVideo().clear();
}
}
[/as]

Si vous souhaitez conservez la dimension vous devez passer par les propriétés width et height du nouvel objet Video. Le constructor de l’ objet Video ne fonctionne qu’ une seule fois…

[as]
var _video1 : Video = new Video(500, 400);
var _video2 : Video = new Video(200, 200);

trace(“_video2.width:” + _video2.width);// 500 !
trace(“_video2.height:” + _video2.height);// 400 !
[/as]

[as]
if(_video.getVideo().smoothing) {
_video.removeVideo();

// new Video( _video.getVideo().width, _video.getVideo().height )// not working

var v : Video = new Video();
v.width = _video.getVideo().width;
v.height = _video.getVideo().height;

_video.setVideo(v);
_video.addVideo();
} else {
_video.getVideo().clear();
}
[/as]

Bien, j’espère que vous aurez apprécié ces quelques clarifications et apprécierez, pour ceux d’ entre vous qui ne la connaissaient pas encore, l’ utilisation de la classe VideoDisplay de LowRA. Vos remarques sont attendues !

VideoDisplayExtended.as (226)
VideoDisplayTest.zip (251)

Bugs, Featured, Flash Player, LowRA

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Comments

5 Responses to “Le point sur NetStream.close(), le bug Video.smoothing/ Video.clear() et la classe VideoDisplay de LowRA”

Leave Comment

(required)

(required)


eXTReMe Tracker