【问题标题】:Flex: Restore Spark VideoDisplay streamFlex:恢复 Spark VideoDisplay 流
【发布时间】:2012-01-15 14:07:01
【问题描述】:

编辑 如果有人至少可以告诉我在流断开连接时如何接收事件,那就太好了。

这个控件的文档简直太可怕了。我有一个具有实时视频流的应用程序,我正在寻找一种方法来使 VideoDisplay 控件在发生以下任何特定情况时恢复其连接:

  1. 应用程序启动,但流尚未在线。
  2. 应用程序正在流式传输,用户已断开与 Internet 的连接。
  3. 应用程序正在流式传输,视频服务器崩溃并重新启动。

我正在使用 Wowza Media Server 和 Wirecast 进行测试。 1 和 3 不起作用,我不确定 2 是否起作用。我通过添加这段非常有问题的代码来完成第 1 项工作:

    protected function onMediaPlayerStateChange(event:MediaPlayerStateChangeEvent):void
    {
        if (event.state == MediaPlayerState.PLAYBACK_ERROR)
        {
            var videoSource:DynamicStreamingVideoSource = this.videoDisplay.source as DynamicStreamingVideoSource;

            try
            {
                this.videoDisplay.source = null;
                this.videoDisplay.source = videoSource;
            }
            catch (any:*) {}
        }
    }

如您所见,我需要一个 try/catch 块,因为对 source 的两个调用都会导致异常,但是在这些异常之前发生的任何事情似乎都可以解决问题 #1。这并不能解决问题 #3,因为当您停止视频服务器时显然不会发生媒体状态更改事件。

这是我的控制声明:

<s:VideoDisplay id="videoDisplay" click="onVideoStreamClick(event)" mediaPlayerStateChange="onMediaPlayerStateChange(event)" muted="{this.videoMuted}" top="10" width="280" height="220" autoPlay="true" horizontalCenter="0">
    <s:source>
        <s:DynamicStreamingVideoSource id="videoSource" streamType="live" host="{FlexGlobals.topLevelApplication.parameters.videoStreamURL}">
            <s:DynamicStreamingVideoItem id="videoItemLow" streamName="{FlexGlobals.topLevelApplication.parameters.videoLow}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoLowBitrate}" />
            <s:DynamicStreamingVideoItem id="videoItemMedium" streamName="{FlexGlobals.topLevelApplication.parameters.videoMedium}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoMediumBitrate}" />
            <s:DynamicStreamingVideoItem id="videoItemHigh" streamName="{FlexGlobals.topLevelApplication.parameters.videoHigh}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoHighBitrate}" />
        </s:DynamicStreamingVideoSource>
    </s:source>
</s:VideoDisplay>

有谁知道如何使 VideoDisplay 从这些问题中恢复?任何帮助表示赞赏,谢谢。

【问题讨论】:

    标签: apache-flex live-streaming flex-spark videodisplay


    【解决方案1】:

    如果有人遇到这个问题,我就是这样解决的。您需要将视频源设置为空白图像才能停止流式传输,否则它将永远不会停止。此解决方案适用于上述所有场景:

        private function resetVideo():void
        {           
            //save current source object
            this.videoEventsDisabled = true;
            var videoSource:DynamicStreamingVideoSource = this.videoDisplay.source as DynamicStreamingVideoSource;
    
            try //switch to blank image, only this will stop the video stream
            {
                this.videoDisplay.source = "assets/images/video_offline.png";
            }
            catch (any:*) {}
    
            //wait a few seconds and reset video source
            setTimeout(resetVideoSource, 2000, videoSource);
        }
    
        private function resetVideoSource(videoSource:DynamicStreamingVideoSource):void
        {
            this.videoEventsDisabled = false;
            this.videoDisplay.source = videoSource;
        }
    
        protected function onMediaPlayerStateChange(event:MediaPlayerStateChangeEvent):void
        {
            if (this.videoEventsDisabled)
            {
                return;
            }
    
            //something went wrong
            if (event.state == MediaPlayerState.PLAYBACK_ERROR)
            {
                resetVideo();
            }
        }
    
        protected function onCurrentTimeChange(event:TimeEvent):void
        {
            if (this.videoEventsDisabled)
            {
                return;
            }
    
            //if there was a number before, and its suddendly NaN, video is offline
            if (isNaN(event.time) && !isNaN(this.previousVideoTime))
            {
                resetVideo();
            }
            else //store event time for future comparisons
            {
                this.previousVideoTime = event.time;
            }
        }
    

    MXML:

    <s:VideoDisplay id="videoDisplay" click="onVideoStreamClick(event)" mediaPlayerStateChange="onMediaPlayerStateChange(event)" currentTimeChange="onCurrentTimeChange(event)" muted="{this.videoMuted}" top="10" width="280" height="220" autoPlay="true" horizontalCenter="0">
        <s:source>
            <s:DynamicStreamingVideoSource id="videoSource" streamType="live" host="{FlexGlobals.topLevelApplication.parameters.videoStreamURL}">
                <s:DynamicStreamingVideoItem id="videoItemLow" streamName="{FlexGlobals.topLevelApplication.parameters.videoLow}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoLowBitrate}" />
                <s:DynamicStreamingVideoItem id="videoItemMedium" streamName="{FlexGlobals.topLevelApplication.parameters.videoMedium}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoMediumBitrate}" />
                <s:DynamicStreamingVideoItem id="videoItemHigh" streamName="{FlexGlobals.topLevelApplication.parameters.videoHigh}" bitrate="{FlexGlobals.topLevelApplication.parameters.videoHighBitrate}" />
            </s:DynamicStreamingVideoSource>
        </s:source>
    </s:VideoDisplay>
    

    【讨论】:

      【解决方案2】:

      作为一种变体,您可以从 NetStream 对象处理 NetStream.Play.PublishNotify。

      var _source:DynamicStreamingResource;
      _source = new DynamicStreamingResource("rtmp://...", StreamType.LIVE);
      
      var streamItems:Vector.<DynamicStreamingItem> = new Vector.<DynamicStreamingItem>();
      streamItems.push(new DynamicStreamingItem(streamName, 0));
      
      _source.streamItems = streamItems;
      
      _rtmpDynamicStreamingNetLoader = new RTMPDynamicStreamingNetLoader();
      _rtmpDynamicStreamingNetLoader.addEventListener(LoaderEvent.LOAD_STATE_CHANGE, rtmpDynamicStreamingNetLoaderStateChangeHandler);
      
      var cvp:VideoDisplay = new VideoDisplay();
      
      _source.mediaType = MediaType.VIDEO;
      
      var videoElement:MediaElement = new VideoElement(_source, _rtmpDynamicStreamingNetLoader);
      
      cvp.source = videoElement;
      
      private function rtmpDynamicStreamingNetLoaderStateChangeHandler(event:LoaderEvent):void
      {
          var netStream:NetStream = event.loadTrait["netStream"] as NetStream;
          if (netStream != null && !netStream.hasEventListener(NetStatusEvent.NET_STATUS)) {
              netStream.addEventListener(NetStatusEvent.NET_STATUS, netStreamNetStatusHandler, false, 0, true);
          }
      }
      
      private function netStreamNetStatusHandler(event:NetStatusEvent):void
      {
          if (event.info.code == "NetStream.Play.UnpublishNotify") {
      
          }
          if (event.info.code == "NetStream.Play.PublishNotify") {
      
          }
       }
      

      【讨论】:

        【解决方案3】:

        我使用 Johnatan 的代码和 JayPea 的想法来解决我的问题!

        我使用了 Johnatan 提供的所有内容,并在 netStreamNetStatusHandler() 中进行了以下小改动:

        private function netStreamNetStatusHandler(event:NetStatusEvent):void
        {
            trace(event.info.code);
        
            if (event.info.code == "NetStream.Play.PublishNotify")
            {
                try
                {
                    cvp.source = ''; //Doesn't need to be a valid path. Empty string should suffice.
                }
                catch (error:Error)
                {
                    trace('Video source error: ' + error.message);
                }
        
                cvp.source = videoElement;
            }
        }
        

        这会在流停止并重新启动时重置源,从而导致视频显示再次播放。

        注意:视频显示的 autoPlay 属性需要设置为“true”。

        【讨论】:

          【解决方案4】:

          我知道这个问题是多年前提出的,但它仍然帮助我解决了我的问题,鼓励我深入研究 VideoDisplay 的来源(因为显然没有“干净”的解决方案 ;-(

          对于那些有同样问题的人,我的“解决方案”也可能会有所帮助:

          在用户单击中止后,我不得不重新启动相同的视频,但随后又决定再次播放。如果不“重置” VideoDisplay,则会导致黑屏。

          在我发现在 VideoDisplay 中,当在 commitProperties() 函数中未定义 thumnailSource 时调用了内部函数“setupSource()”后,我解决了这个问题。

          由于 setupSource() 函数不能公开访问,我使用了这个:

                  myVideoDisplaySpark.enabled = false; // changes properties
                  myVideoDisplaySpark.source = "";    // does not harm ;-)
                  myVideoDisplaySpark.mx_internal::thumbnailSource = null; // forces a setupSource in commitProperties
                  myVideoDisplaySpark.enabled = true;  // finally results in the call if setupSource
          

          至少我是这么理解的;最后它对我有用;-)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-01-22
            • 1970-01-01
            • 2010-10-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-22
            相关资源
            最近更新 更多