Im Artikel Dynamic Streaming mit dem Flash Media Server wurde bereits das Dynamic Streaming beschrieben. Zur Veranschaulichung des Streamwechsel habe ich dem dynamischen Stream vier Videos (01.flv bis 04.flv) zugeordnet, die unterschiedliche Kameraperspektiven haben. Das Beispiel zeigt, wie man manuell zwischen diesen Streams umschalten kann.

Demo anschauen

Da ich keinen Flash Media Server im Netz habe, habe ich einen kurzen Screencast erstellt:

Get Adobe Flash player

Videomaterial

Die Videos sind alle gleich lang und wurden mit identischen Einstellungen kodiert. Die zugeordneten Bitraten von 100 bis 400 im ActionScript-Code sind also beliebig gewählt und stimmen nicht.

Actionscript:
  1. dsi.addStream("01", 100)
  2. dsi.addStream("02", 200)
  3. dsi.addStream("03", 300)
  4. dsi.addStream("04", 400);

Die Audiospur ist bei allen Videos gleich. Es ist schön zu hören, dass auf der Audioebene überhaupt kein Wechsel zwischen den Streams hörbar ist.

manualSwitchMode()

Die Methode manualSwitchMode(mode:Boolean) der DynamicStream-Klasse dient eigentlich nur als Demonstration oder zu Testzwecken. Übergibt man true, kann man danach manuell zwischen den verschiedenen Streams springen.

Toggles between manual switch mode and automatic switch mode in the DynamicStream class. When set to true, you can use the methods switchToStreamName(), switchToStreamRate(), switchUp(), and switchDown() to control the class. When set to false, the methods are not available.

Um auf den DynamicStream der FLV Playback Komponente zugreifen zu können, muss man sich bis zum NetStream-Objekt durchhangeln. Da die DynamicStream-Klasse von der NetStream-Klasse erbt, wandelt man die NetStream-Instanz in einen dynamischen Stream um. Die Zeile lautet: ds = DynamicStream(myFLVPlayback.ncMgr.videoPlayer.netStream);

Jetzt kann man z.B. mit ds.switchToStreamRate(200) auf den zweiten Stream wechseln.

Buffer

Vor dem Wechsel zu einem anderen Stream wird jedoch zuerst das restliche Videomaterial abspielt, das sich noch im Buffer befindet. Es kommt zu einer Verzögerung. Ist der Buffer leer, wird an der nächstmöglichen Stelle auf den anderen Stream gesprungen. Damit die Streams schneller wechseln, habe ich die Bufferzeiten im Beispiel heruntergesetzt.

Informationen aus dem DynamicStream

Interessant sind auch die Werte, die sich aus dem DynamicStream-Objekt auslesen lassen. Dazu gehören z.B.

  • der Name des aktuellen Streams
  • die aktuelle Bitrate
  • verschiedene Bufferzeiten
  • Anzahl der dropped Frames
  • vieles mehr

Sourcecode

Der Quellcode der Beispielanwendung lautet:

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. :Application xmlns:mx="http://www.adobe.com/2006/mxml"
  3.     creationComplete="onCreationComplete()"
  4.     backgroundColor="#000000" layout="absolute">
  5.     :Script>
  6.        
  7.             import mx.events.DynamicEvent;
  8.             import fl.video.*;
  9.            
  10.             private var myFLVPlayback:FLVPlayback;
  11.            
  12.             [Bindable]
  13.             private var ds:DynamicStream;
  14.            
  15.             [Bindable]
  16.             private var myText:String;
  17.            
  18.             private function onCreationComplete():void  {
  19.                
  20.                 // FLV Playback Komponente
  21.                 VideoPlayer.iNCManagerClass = NCManagerDynamicStream;         
  22.                 myFLVPlayback = new FLVPlayback();
  23.                 ui.addChild( myFLVPlayback );
  24.                 
  25.                 // Skin
  26.                 myFLVPlayback.skin = "SkinUnderPlaySeekMute.swf";
  27.                 myFLVPlayback.skinBackgroundColor = 0x5F7205;
  28.                    
  29.                 // neuer Dynamic Stream 
  30.                 var dsi:DynamicStreamItem = new DynamicStreamItem(); 
  31.                 dsi.uri = "rtmp://192.168.2.108/vod/"; 
  32.                 dsi.addStream("01", 100); 
  33.                 dsi.addStream("02", 200); 
  34.                 dsi.addStream("03", 300); 
  35.                 dsi.addStream("04", 400);      
  36.        
  37.                 // Play
  38.                 myFLVPlayback.play2(dsi);
  39.                        
  40.                 // Event Listener         
  41.                 myFLVPlayback.addEventListener(VideoEvent.READY, onReady);
  42.                 this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
  43.             }
  44.  
  45.            
  46.             private function onEnterFrame(e:Event):void {
  47.  
  48.                 if (ds != null) {
  49.                     // Textfeld aktualisieren               
  50.                     myText = "Current Stream Name: " + ds.currentStreamName + "\n";     
  51.                     myText += "Current Stream Bitrate: " + String(ds.currentStreamBitRate) + "\n";
  52.                     myText += "Buffer: " + String (myFLVPlayback.bufferTime)+ "\n";
  53.                     myText += "startBufferLength: " + String (ds.startBufferLength)+ "\n";         
  54.                     myText += "Preferred Buffer Length: " + String (ds.preferredBufferLength)+ "\n";   
  55.                     myText += "Dropped Frames: " + ds.info.droppedFrames;  
  56.                 }
  57.                
  58.                
  59.             }
  60.            
  61.             private function onReady(e:VideoEvent):void {
  62.                
  63.                 // DynamicStream-Objekt aus dem NetStream der Komponente referenzieren
  64.                 ds = DynamicStream(myFLVPlayback.ncMgr.videoPlayer.netStream);
  65.                
  66.                 // Auf manuellen Mode setzen
  67.                 ds.manualSwitchMode(true);
  68.                
  69.                 // Buffer heruntersetzen, damit der Wechsel schneller vollzogen wird
  70.                 ds.preferredBufferLength = 1;
  71.                 myFLVPlayback.bufferTime = 1;
  72.             }
  73.            
  74.         ]]>
  75.     :Script>
  76.    
  77.  
  78.    
  79.     :HBox y="5">
  80.         :Button label="Cam 1" click="ds.switchToStreamRate(100)" />
  81.         :Button label="Cam 2" click="ds.switchToStreamRate(200)" />
  82.         :Button label="Cam 3" click="ds.switchToStreamRate(300)" />   
  83.         :Button label="Cam 4" click="ds.switchToStreamRate(400)" />     
  84.     :HBox>
  85.    
  86.     :UIComponent id="ui" y="50" />
  87.  
  88.     :Text text="{myText}" y="50" x="350" color="#ffffff" />
  89.    
  90.    
  91. :Application>