private void OnAllSubPlayListLoaded()
        {
            // DoCloseMedia may happend before the AllSubPlayListEvent event fired.
            if (_playlist == null || _program == null) return;

            uint maxBitrate = 0;
            _playback.AllSubPlayListEvent -= OnAllSubPlayListLoaded;
            foreach (HLSVariant hlsVariant in _program.Variants)
            {
                hlsVariant.Playback = null;
                if (hlsVariant.Bitrate > maxBitrate)
                {
                    maxBitrate = hlsVariant.Bitrate;
                }
            }

            //
            // Allocate video buffer based on max bitrate and buffer length plus 10 extra seconds of pending chunk progressive
            // downloading / parsing.
            // Minimal initial buffer size is 5MB (corresponding 1Mb bitrate) in case playlist returns unreasonable low bitrate.
            // Max initial buffer size is 50MB (corrsponding 10Mb bitrate) in case playlist returns unsupported high bitrate.
            //
            int initialVideoBufferSize = Math.Max((int)((_bufferLength.TotalSeconds + 10) * maxBitrate / 8), 5 * 1024 * 1024);
            initialVideoBufferSize = Math.Min(initialVideoBufferSize, 50 * 1024 * 1024);
            _videoBuffer = new SampleBuffer(initialVideoBufferSize);
            // Allocate audio buffer based on 256Kb audio bitrate and buffer length plus 10 extra seconds of pending chunk progressive
            // downloading / parsing.
            _audioBuffer = new SampleBuffer((int)((_bufferLength.TotalSeconds + 10) * 256 * 1024) / 8);

            PlayListOverrideInfo overrideInfo = new PlayListOverrideInfo();
            overrideInfo.reason = PlayListOverrideReason.ePlaylistLoaded;
            overrideInfo.position = TimeSpan.Zero;
            OverridePlaylistIfNecessary(overrideInfo);

            if (_playback.Program == null)
                _playback.Program = _program;

            if (_playback.BeginGetNextStream(new AsyncCallback(AsyncStreamCallback), _playback) == null)
            {
                RaiseError("unable to open stream");
            }
        }
        private bool OverridePlaylistIfNecessary(PlayListOverrideInfo overrideInfo)
        {
            bool isOverrided = false;
            if (null != _playlistOverrideEvent)
            {
                HLSExternalPlayListImpl externalPlayLsit = new HLSExternalPlayListImpl();
                if (overrideInfo.reason == PlayListOverrideReason.ePlaylistLoaded)
                {
                    externalPlayLsit.FromHLSPlaylist(_playlist);
                }
                if (_playlistOverrideEvent(externalPlayLsit, overrideInfo))
                {
                    isOverrided = true;
                    _playlist.FromHLSExternalPlaylist(externalPlayLsit);
                    lock (_playback)
                    {
                        _program = _playlist.Programs[0];
                        _playback.Program = _program;
                        _playback.ResetPlayback(_program, _playlist.PlaylistDuration);

                        List<SampleBuffer.TimeLineInfo> timelineInfoList = new List<SampleBuffer.TimeLineInfo>();
                        foreach (TimelineEstablishInfo establishInfo in externalPlayLsit.timelineEstablishInfoList)
                        {
                            timelineInfoList.Add(new SampleBuffer.TimeLineInfo(establishInfo.timelineStartOffset.Ticks, establishInfo.isMonoIncrease));
                        }
                        _videoBuffer.EstablishTimeline(timelineInfoList);
                        _audioBuffer.EstablishTimeline(timelineInfoList);
                    }
                }
            }

            if (!isOverrided && overrideInfo.reason == PlayListOverrideReason.ePlaylistLoaded)
            {
                List<SampleBuffer.TimeLineInfo> timelineInfoList = new List<SampleBuffer.TimeLineInfo>();
                timelineInfoList.Add(new SampleBuffer.TimeLineInfo(0, false));

                _videoBuffer.EstablishTimeline(timelineInfoList);
                _audioBuffer.EstablishTimeline(timelineInfoList);
            }

            _playlistOverrided = isOverrided;
            return isOverrided;
        }
        /// <summary>
        /// Handler for Seek command
        /// </summary>
        /// <param name="seekToTime"></param>
        private void DoSeek(long seekToTime)
        {
            HLSTrace.WriteLine("HLS MSS DoSeek, seek time {0} Hns", seekToTime);

            if (_noSeekYet && _noSampleRequestYet && 0 == seekToTime)
            {
                // There is no need to cancel download and start download again for the very first seek
                _noSeekYet = false;
                return;
            }
            _noSeekYet = false;

            // If a stream download is in progress using HttpWebRequest, then this call will flag
            // that request to discard its download stream. The playback impl will not
            // start any new stream download until ResumeDownloads is called. After this call,
            // no more data should be pushed into TSDemux or audio/video buffers.
            _playback.AbortStreamDownloads();
            // Clear work queue as after _playback.AbortStreamDownloads() there shouldn't be any pending NextStream work queue items
            _workQueue.Clear(WorkQueueElement.Command.NextStream);
            _isBuffering = false;
            _audioBuffer.EndOfPlayback = false;
            _videoBuffer.EndOfPlayback = false;
            ReportPendingSamples();

            // Flush and discard all data that are in the TSDemux or audio/video buffers
            _demux.Flush(false);
            _demux.Dispose();
            _demux = null;
            _audioBuffer.Flush();
            _videoBuffer.Flush();

            PlayListOverrideInfo overrideInfo = new PlayListOverrideInfo();
            overrideInfo.reason = PlayListOverrideReason.eSeek;
            overrideInfo.position = new TimeSpan(seekToTime);
            if (!OverridePlaylistIfNecessary(overrideInfo))
            {
                // This will find the .ts stream that should contain the seek point, and would
                // position the playback's stream index to point to that stream.
                _playback.FindSeekStream(seekToTime);
            }
            if (Playback.CurrentStream != null)
            {
                _audioBuffer.ResetTSRollverOffset();
            }
            _lastSeekPlaylistPosition = _playback.CurrentPosition;

            _playback.ResumeDownloads();

            // enter buffering mode right after seek
            _isBuffering = true;

            TSDemux currentTSDemux = _demux;

            if (_playback.BeginGetNextStream(new AsyncCallback(AsyncStreamCallback), _playback) == null)
                RaiseError("unable to open stream");
        }