1 Reply Latest reply on Nov 1, 2010 9:25 AM by bringrags

    Preloading Performance Issue

    claygt

      Hi All,

       

      My application plays a video, while it loads additional videos in the background. After one video is done, the next one plays. The user is presented with options every now and then at the end of the video which may change which video plays next. In general, we try to stay several videos ahead of them in our preload queue, and account for any direction they may go in as to not have an interruption in the video experience.

       

      I've implemented all of this without a problem, but I have one issue that's causing us some trouble. When I preload the video, I have to do the play/pause on the video and then seek to (0) in order to make sure the video is ready to play at a split-second notice. When I perform this preload action while another video is playing on the stage, I see a noticeable hiccup in the video. From what some of our users tell us, on older machines, this stutter is exaggerated. I'm assuming that this play/pause/seek combination is fairly processor intensive? Is there another way I could approach this? It's important that I'm able to go from one video ending to the start of a preloaded video without no gap at all.

       

      Thanks in advance for any help. Let me know if I need to clarify or post any specific part of the code. I've used several different preloading approaches, but the one I'm using right now is:

       

      1) Set up my VideoElement and add it to a MediaPlayer (http progressive download).

      2) Listen for the MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE event and make sure canSeek == true;

      3) Call play(). Call pause(). Call seek(0).

      4) Listen for the video to end with TimeEvent.COMPLETE.

       

      Thanks!

      Clay

        • 1. Re: Preloading Performance Issue
          bringrags Level 4

          I would probably try to break up step #3 into separate asynchronous calls.  For one thing, we've noticed that calling pause immediately after the play doesn't always work for multi-bitrate streams.  A more optimal approach is to wait a few hundred milliseconds after the play call before calling pause.  This might also help your case, by breaking up the operations so that the AS executes in different frames.

           

          Here's a nippet from the method we use to execute this logic in our preloading class (which differs slightly from the one in public trunk):


                          // Begin playback.  But don't pause immediately, as doing so for MBR
                          // streams seems to put them in a bad state.
                          playTrait.play();
                         
                          var timer:Timer = new Timer(500, 1);
                          timer.addEventListener(TimerEvent.TIMER, onTimer);
                          timer.start();
                         
                          function onTimer(event:TimerEvent):void
                          {
                              timer.removeEventListener(TimerEvent.TIMER, onTimer);

           

                              // Now pause the stream and seek back to the start.
                              playTrait.pause();
                             
                              // It's possible that the media isn't seekable yet, in which
                              // case we must wait until it is.
                              var seekTrait:SeekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait;
                              if (seekTrait != null)
                              {
                                  // Seek back to the start.
                                  seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange);
                                  seekTrait.seek(0);
                                 
                                  function onSeekingChange(event:SeekEvent):void
                                  {
                                      if (event.seeking == false)
                                      {
                                          seekTrait.removeEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange);
                                         
                                          // Restore the original muted state, and signal we're loaded.
                                          audioTrait.muted = previousMuted;
             
                                          calculatedLoadState = LoadState.READY;
                                          dispatchEvent(eventToDispatch);
                                      }
                                  }
                              }
                              else
                              {
                                  proxiedElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd);
                                 
                                  function onTraitAdd(event:MediaElementEvent):void
                                  {
                                      if (event.traitType == MediaTraitType.SEEK)
                                      {
                                          proxiedElement.removeEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd);

           

                                          // Now we can seek back to the start.
                                          seekTrait = proxiedElement.getTrait(MediaTraitType.SEEK) as SeekTrait;
                                          seekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onSeekingChange);
                                          seekTrait.seek(0);
                                      }
                                  }
                              }
                          }
                      }
                      else
                      {
                          dispatchEvent(eventToDispatch);
                      }
                  }