예제 #1
0
        // Worker thread
        private void WorkerThread()
        {
            // buffer to read stream
            var buffer   = new byte[BufSize];
            var encoding = new ASCIIEncoding();
            var res      = ReasonToFinishPlaying.StoppedByUser;

            while (!_stopEvent.WaitOne(0, false) && !MainForm.ShuttingDown)
            {
                // reset reload event
                _reloadEvent.Reset();

                // HTTP web request
                HttpWebRequest request = null;
                // web responce
                WebResponse response = null;
                // stream for MJPEG downloading
                Stream stream = null;
                // boundary between images (string and binary versions)

                try
                {
                    // create request
                    request = (HttpWebRequest)WebRequest.Create(_source);
                    // set user agent
                    if (_userAgent != null)
                    {
                        request.UserAgent = _userAgent;
                    }

                    // set proxy
                    if (_proxy != null)
                    {
                        request.Proxy = _proxy;
                    }

                    if (_usehttp10)
                    {
                        request.ProtocolVersion = HttpVersion.Version10;
                    }

                    // set timeout value for the request
                    request.Timeout           = request.ServicePoint.ConnectionLeaseTimeout = request.ServicePoint.MaxIdleTime = _requestTimeout;
                    request.AllowAutoRedirect = true;

                    // set login and password
                    if ((_login != null) && (_password != null) && (_login != string.Empty))
                    {
                        request.Credentials = new NetworkCredential(_login, _password);
                    }
                    // set connection group name
                    if (_useSeparateConnectionGroup)
                    {
                        request.ConnectionGroupName = GetHashCode().ToString();
                    }
                    // get response
                    response = request.GetResponse();

                    // get response stream
                    stream             = response.GetResponseStream();
                    stream.ReadTimeout = _requestTimeout;

                    byte[] boundary = encoding.GetBytes("--myboundary");
                    byte[] sep      = encoding.GetBytes("\r\n\r\n");

                    // loop

                    int startPacket = -1;
                    int endPacket   = -1;
                    int ttl         = 0;

                    bool hasaudio = false;

                    while ((!_stopEvent.WaitOne(0, false)) && (!_reloadEvent.WaitOne(0, false)))
                    {
                        int read;
                        if ((read = stream.Read(buffer, ttl, ReadSize)) == 0)
                        {
                            throw new ApplicationException();
                        }

                        ttl += read;

                        if (startPacket == -1)
                        {
                            startPacket = ByteArrayUtils.Find(buffer, boundary, 0, ttl);
                        }
                        else
                        {
                            if (endPacket == -1)
                            {
                                endPacket = ByteArrayUtils.Find(buffer, boundary, startPacket + boundary.Length, ttl - (startPacket + boundary.Length));
                            }
                        }



                        if (startPacket > -1 && endPacket > startPacket)
                        {
                            int br = ByteArrayUtils.Find(buffer, sep, startPacket, 100);

                            if (br != -1)
                            {
                                var arr = new byte[br];
                                System.Array.Copy(buffer, startPacket, arr, 0, br - startPacket);
                                string s = Encoding.ASCII.GetString(arr);
                                int    k = s.IndexOf("Content-type: ", StringComparison.Ordinal);
                                if (k != -1)
                                {
                                    s = s.Substring(k + 14);
                                    s = s.Substring(0, s.IndexOf("\r\n", StringComparison.Ordinal));
                                    s = s.Trim();
                                }
                                switch (s)
                                {
                                case "image/jpeg":
                                    try
                                    {
                                        using (var ms = new MemoryStream(buffer, br + 4, endPacket - br - 8))
                                        {
                                            var bitmap = (Bitmap)Image.FromStream(ms);
                                            // notify client
                                            NewFrame(this, new NewFrameEventArgs(bitmap));
                                            // release the image
                                            bitmap.Dispose();
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        //sometimes corrupted packets come through...
                                        MainForm.LogExceptionToFile(ex);
                                    }


                                    break;

                                case "audio/raw":
                                    if (!hasaudio)
                                    {
                                        hasaudio = true;
                                        //fixed 16khz 1 channel format
                                        RecordingFormat = new WaveFormat(16000, 16, 1);

                                        _waveProvider = new BufferedWaveProvider(RecordingFormat)
                                        {
                                            DiscardOnBufferOverflow = true, BufferDuration = TimeSpan.FromMilliseconds(500)
                                        };

                                        _sampleChannel = new SampleChannel(_waveProvider);
                                        _sampleChannel.PreVolumeMeter += SampleChannelPreVolumeMeter;
                                        if (HasAudioStream != null)
                                        {
                                            HasAudioStream(this, EventArgs.Empty);
                                            HasAudioStream = null;
                                        }
                                    }

                                    var da = DataAvailable;
                                    if (da != null)
                                    {
                                        int l    = endPacket - br - 8;
                                        var data = new byte[l];
                                        int d    = 0;
                                        using (var ms = new MemoryStream(buffer, br + 4, l))
                                        {
                                            d = ms.Read(data, 0, l);
                                        }
                                        if (d > 0)
                                        {
                                            _waveProvider.AddSamples(data, 0, data.Length);

                                            if (Listening)
                                            {
                                                WaveOutProvider.AddSamples(data, 0, data.Length);
                                            }

                                            //forces processing of volume level without piping it out
                                            var sampleBuffer = new float[data.Length];
                                            _sampleChannel.Read(sampleBuffer, 0, data.Length);

                                            da(this, new DataAvailableEventArgs((byte[])data.Clone()));
                                        }
                                    }

                                    break;

                                case "alert/text":
                                    // code to handle alert notifications goes here
                                    if (AlertHandler != null)
                                    {
                                        int dl    = endPacket - br - 8;
                                        var data2 = new byte[dl];
                                        using (var ms = new MemoryStream(buffer, br + 4, dl))
                                        {
                                            ms.Read(data2, 0, dl);
                                        }
                                        string alerttype = Encoding.ASCII.GetString(data2);
                                        AlertHandler(this, new AlertEventArgs(alerttype));
                                    }
                                    break;
                                }
                            }

                            ttl -= endPacket;
                            System.Array.Copy(buffer, endPacket, buffer, 0, ttl);
                            startPacket = -1;
                            endPacket   = -1;
                        }
                    }
                }
                catch (ApplicationException)
                {
                    // do nothing for Application Exception, which we raised on our own
                    // wait for a while before the next try
                    Thread.Sleep(250);
                }
                catch (ThreadAbortException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    // provide information to clients
                    MainForm.LogExceptionToFile(ex);
                    res = ReasonToFinishPlaying.DeviceLost;
                    break;
                    // wait for a while before the next try
                    //Thread.Sleep(250);
                }
                finally
                {
                    // abort request
                    if (request != null)
                    {
                        try
                        {
                            request.Abort();
                        }
                        catch
                        {
                        }
                        request = null;
                    }
                    // close response stream
                    if (stream != null)
                    {
                        try
                        {
                            stream.Flush();
                        }
                        catch
                        {
                        }
                        try
                        {
                            stream.Close();
                        }
                        catch
                        {
                        }
                        try
                        {
                            stream.Dispose();
                        }
                        catch { }
                        stream = null;
                    }
                    // close response
                    if (response != null)
                    {
                        try
                        {
                            response.Close();
                        }
                        catch
                        {
                        }
                        response = null;
                    }
                }

                // need to stop ?
                if (_stopEvent.WaitOne(0, false))
                {
                    break;
                }
            }

            if (PlayingFinished != null)
            {
                PlayingFinished(this, res);
            }
        }
예제 #2
0
        // Worker thread
        private void WorkerThread()
        {
            // buffer to read stream
            var buffer = new byte[BufSize];
            // JPEG magic number
            var jpegMagic = new byte[] { 0xFF, 0xD8, 0xFF };


            var encoding = new ASCIIEncoding();
            var res      = ReasonToFinishPlaying.StoppedByUser;

            while (!_stopEvent.WaitOne(0, false))
            {
                // reset reload event
                _reloadEvent.Reset();

                // HTTP web request
                HttpWebRequest request = null;
                // web response
                WebResponse response = null;
                // stream for MJPEG downloading
                Stream stream = null;
                // boundary between images (string and binary versions)
                byte[] boundary;
                string boudaryStr = null;
                // length of boundary
                // flag signaling if boundary was checked or not
                bool boundaryIsChecked = false;
                // read amounts and positions
                int todo = 0, total = 0, pos = 0, align = 1;
                int start = 0;

                // align
                //  1 = searching for image start
                //  2 = searching for image end

                try
                {
                    // create request
                    request = GenerateRequest(_source);
                    // get response
                    response = request.GetResponse();

                    // check content type
                    string   contentType      = response.ContentType;
                    string[] contentTypeArray = contentType.Split('/');

                    // "application/octet-stream"
                    int boundaryLen;
                    if ((contentTypeArray[0] == "application") && (contentTypeArray[1] == "octet-stream"))
                    {
                        boundaryLen = 0;
                        boundary    = new byte[0];
                    }
                    else if ((contentTypeArray[0] == "multipart") && (contentType.Contains("mixed")))
                    {
                        // get boundary
                        int boundaryIndex = contentType.IndexOf("boundary", 0, StringComparison.Ordinal);
                        if (boundaryIndex != -1)
                        {
                            boundaryIndex = contentType.IndexOf("=", boundaryIndex + 8, StringComparison.Ordinal);
                        }

                        if (boundaryIndex == -1)
                        {
                            // try same scenario as with octet-stream, i.e. without boundaries
                            boundaryLen = 0;
                            boundary    = new byte[0];
                        }
                        else
                        {
                            boudaryStr = contentType.Substring(boundaryIndex + 1);
                            // remove spaces and double quotes, which may be added by some IP cameras
                            boudaryStr = boudaryStr.Trim(' ', '"');

                            boundary          = encoding.GetBytes(boudaryStr);
                            boundaryLen       = boundary.Length;
                            boundaryIsChecked = false;
                        }
                    }
                    else
                    {
                        if (contentType == "text/html")
                        {
                            try
                            {
                                //read body
                                var sr   = new StreamReader(response.GetResponseStream());
                                var html = sr.ReadToEnd();
                                if (html.IndexOf("setup_kakulens.html", StringComparison.Ordinal) != -1)
                                {
                                    //hack for panasonic cameras that redirect on reboot in privacy mode - POST a command to disable privacy
                                    if (DisablePrivacy(request))
                                    {
                                        _needsPrivacyEnabledTarget = Helper.Now.AddSeconds(4);
                                        _needsPrivacyEnabled       = true;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                MainForm.LogExceptionToFile(ex);
                            }
                            //continue to throw the invalid content type error as the next retry should connect
                        }
                        throw new Exception("Invalid content type.");
                    }

                    // get response stream
                    stream             = response.GetResponseStream();
                    stream.ReadTimeout = _requestTimeout;

                    // loop
                    while ((!_stopEvent.WaitOne(0, false)) && (!_reloadEvent.WaitOne(0, false)))
                    {
                        // check total read
                        if (total > BufSize - ReadSize)
                        {
                            total = pos = todo = 0;
                        }

                        // read next portion from stream
                        int read;
                        if ((read = stream.Read(buffer, total, ReadSize)) == 0)
                        {
                            throw new ApplicationException();
                        }

                        total += read;
                        todo  += read;

                        // increment received bytes counter
                        _bytesReceived += read;

                        // do we need to check boundary ?
                        if ((boundaryLen != 0) && (!boundaryIsChecked))
                        {
                            // some IP cameras, like AirLink, claim that boundary is "myboundary",
                            // when it is really "--myboundary". this needs to be corrected.

                            pos = ByteArrayUtils.Find(buffer, boundary, 0, todo);
                            // continue reading if boudary was not found
                            if (pos == -1)
                            {
                                continue;
                            }

                            for (int i = pos - 1; i >= 0; i--)
                            {
                                byte ch = buffer[i];

                                if ((ch == (byte)'\n') || (ch == (byte)'\r'))
                                {
                                    break;
                                }

                                boudaryStr = (char)ch + boudaryStr;
                            }

                            boundary          = encoding.GetBytes(boudaryStr);
                            boundaryLen       = boundary.Length;
                            boundaryIsChecked = true;
                        }

                        // search for image start
                        if ((align == 1) && (todo >= jpegMagic.Length))
                        {
                            start = ByteArrayUtils.Find(buffer, jpegMagic, pos, todo);
                            if (start != -1)
                            {
                                // found JPEG start
                                pos   = start + jpegMagic.Length;
                                todo  = total - pos;
                                align = 2;
                            }
                            else
                            {
                                // delimiter not found
                                todo = jpegMagic.Length - 1;
                                pos  = total - todo;
                            }
                        }

                        // search for image end ( boundaryLen can be 0, so need extra check )
                        while ((align == 2) && (todo != 0) && (todo >= boundaryLen))
                        {
                            int stop = ByteArrayUtils.Find(buffer,
                                                           (boundaryLen != 0) ? boundary : jpegMagic,
                                                           pos, todo);

                            if (stop != -1)
                            {
                                // increment frames counter
                                _framesReceived++;

                                // image at stop
                                if ((NewFrame != null) && (!_stopEvent.WaitOne(0, false)))
                                {
                                    if (!String.IsNullOrEmpty(DecodeKey))
                                    {
                                        byte[] marker = Encoding.ASCII.GetBytes(DecodeKey);

                                        using (var ms = new MemoryStream(buffer, start + jpegMagic.Length, jpegMagic.Length + marker.Length))
                                        {
                                            var key = new byte[marker.Length];
                                            ms.Read(key, 0, marker.Length);

                                            if (!ByteArrayUtils.UnsafeCompare(marker, key))
                                            {
                                                throw (new Exception("Image Decode Failed - Check the decode key matches the encode key on ispy server"));
                                            }
                                        }


                                        using (var ms = new MemoryStream(buffer, start + marker.Length, stop - start - marker.Length))
                                        {
                                            ms.Seek(0, SeekOrigin.Begin);
                                            ms.WriteByte(jpegMagic[0]);
                                            ms.WriteByte(jpegMagic[1]);
                                            ms.WriteByte(jpegMagic[2]);
                                            ms.Seek(0, SeekOrigin.Begin);
                                            using (var bitmap = (Bitmap)Image.FromStream(ms))  {
                                                NewFrame(this, new NewFrameEventArgs(bitmap));
                                            }
                                        }
                                    }
                                    else
                                    {
                                        using (var ms = new MemoryStream(buffer, start, stop - start))
                                        {
                                            using (var bitmap = (Bitmap)Image.FromStream(ms))
                                            {
                                                NewFrame(this, new NewFrameEventArgs(bitmap));
                                            }
                                        }
                                    }

                                    if (_needsPrivacyEnabled && _needsPrivacyEnabledTarget < Helper.Now)
                                    {
                                        if (EnablePrivacy(request))
                                        {
                                            _needsPrivacyEnabled = false;
                                        }
                                    }
                                }

                                // shift array
                                pos  = stop + boundaryLen;
                                todo = total - pos;
                                System.Array.Copy(buffer, pos, buffer, 0, todo);

                                total = todo;
                                pos   = 0;
                                align = 1;
                            }
                            else
                            {
                                // boundary not found
                                if (boundaryLen != 0)
                                {
                                    todo = boundaryLen - 1;
                                    pos  = total - todo;
                                }
                                else
                                {
                                    todo = 0;
                                    pos  = total;
                                }
                            }
                        }
                    }
                }
                catch (ApplicationException)
                {
                    // do nothing for Application Exception, which we raised on our own
                    // wait for a while before the next try
                    Thread.Sleep(250);
                }
                catch (ThreadAbortException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    // provide information to clients
                    MainForm.LogExceptionToFile(ex);
                    res = ReasonToFinishPlaying.DeviceLost;
                    break;
                    // wait for a while before the next try
                    //Thread.Sleep(250);
                }
                finally
                {
                    // abort request
                    if (request != null)
                    {
                        try
                        {
                            request.Abort();
                        }
                        catch {}
                        request = null;
                    }
                    // close response stream
                    if (stream != null)
                    {
                        try
                        {
                            stream.Flush();
                        }
                        catch
                        {
                        }
                        try
                        {
                            stream.Close();
                        }
                        catch
                        {
                        }
                        try
                        {
                            stream.Dispose();
                        }
                        catch {}

                        stream = null;
                    }
                    // close response
                    if (response != null)
                    {
                        try
                        {
                            response.Close();
                        }
                        catch
                        {
                        }
                        response = null;
                    }
                }

                // need to stop ?
                if (_stopEvent.WaitOne(0, false))
                {
                    break;
                }
            }

            if (PlayingFinished != null)
            {
                PlayingFinished(this, res);
            }
        }
예제 #3
0
        // Worker thread
        private void WorkerThread()
        {
            // buffer to read stream
            var buffer = new byte[BufSize];
            // JPEG magic number
            var jpegMagic = new byte[] { 0xFF, 0xD8, 0xFF };


            var encoding = new ASCIIEncoding();

            while (!_stopEvent.WaitOne(0, false))
            {
                // reset reload event
                _reloadEvent.Reset();

                // HTTP web request
                HttpWebRequest request = null;
                // web responce
                WebResponse response = null;
                // stream for MJPEG downloading
                Stream stream = null;
                // boundary betweeen images (string and binary versions)
                byte[] boundary;
                string boudaryStr = null;
                // length of boundary
                // flag signaling if boundary was checked or not
                bool boundaryIsChecked = false;
                // read amounts and positions
                int todo = 0, total = 0, pos = 0, align = 1;
                int start = 0;

                // align
                //  1 = searching for image start
                //  2 = searching for image end

                try
                {
                    // create request
                    request = (HttpWebRequest)WebRequest.Create(_source);
                    // set user agent
                    if (_userAgent != null)
                    {
                        request.UserAgent = _userAgent;
                    }

                    // set proxy
                    if (_proxy != null)
                    {
                        request.Proxy = _proxy;
                    }

                    if (_usehttp10)
                    {
                        request.ProtocolVersion = HttpVersion.Version10;
                    }

                    // set timeout value for the request
                    request.Timeout           = _requestTimeout;
                    request.AllowAutoRedirect = true;
                    ServicePointManager.ServerCertificateValidationCallback += Certificates.ValidateRemoteCertificate;

                    // set login and password
                    if ((_login != null) && (_password != null) && (_login != string.Empty))
                    {
                        request.Credentials = new NetworkCredential(_login, _password);
                    }
                    // set connection group name
                    if (_useSeparateConnectionGroup)
                    {
                        request.ConnectionGroupName = GetHashCode().ToString();
                    }
                    // force basic authentication through extra headers if required

                    var authInfo = "";
                    if (!String.IsNullOrEmpty(_login))
                    {
                        authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(_login + ":" + _password));
                        request.Headers["Authorization"] = "Basic " + authInfo;
                    }


                    if (!String.IsNullOrEmpty(_cookies))
                    {
                        _cookies = _cookies.Replace("[AUTH]", authInfo);
                        var      myContainer = new CookieContainer();
                        string[] coll        = _cookies.Split(';');
                        foreach (var ckie in coll)
                        {
                            if (!String.IsNullOrEmpty(ckie))
                            {
                                string[] nv = ckie.Split('=');
                                if (nv.Length == 2)
                                {
                                    var cookie = new Cookie(nv[0].Trim(), nv[1].Trim());
                                    myContainer.Add(new Uri(request.RequestUri.ToString()), cookie);
                                }
                            }
                        }
                        request.CookieContainer = myContainer;
                    }
                    // get response
                    response = request.GetResponse();

                    // check content type
                    string   contentType      = response.ContentType;
                    string[] contentTypeArray = contentType.Split('/');

                    // "application/octet-stream"
                    int boundaryLen;
                    if ((contentTypeArray[0] == "application") && (contentTypeArray[1] == "octet-stream"))
                    {
                        boundaryLen = 0;
                        boundary    = new byte[0];
                    }
                    else if ((contentTypeArray[0] == "multipart") && (contentType.Contains("mixed")))
                    {
                        // get boundary
                        int boundaryIndex = contentType.IndexOf("boundary", 0);
                        if (boundaryIndex != -1)
                        {
                            boundaryIndex = contentType.IndexOf("=", boundaryIndex + 8);
                        }

                        if (boundaryIndex == -1)
                        {
                            // try same scenario as with octet-stream, i.e. without boundaries
                            boundaryLen = 0;
                            boundary    = new byte[0];
                        }
                        else
                        {
                            boudaryStr = contentType.Substring(boundaryIndex + 1);
                            // remove spaces and double quotes, which may be added by some IP cameras
                            boudaryStr = boudaryStr.Trim(' ', '"');

                            boundary          = encoding.GetBytes(boudaryStr);
                            boundaryLen       = boundary.Length;
                            boundaryIsChecked = false;
                        }
                    }
                    else
                    {
                        throw new Exception("Invalid content type.");
                    }

                    // get response stream
                    stream             = response.GetResponseStream();
                    stream.ReadTimeout = _requestTimeout;

                    // loop
                    while ((!_stopEvent.WaitOne(0, false)) && (!_reloadEvent.WaitOne(0, false)))
                    {
                        // check total read
                        if (total > BufSize - ReadSize)
                        {
                            total = pos = todo = 0;
                        }

                        // read next portion from stream
                        int read;
                        if ((read = stream.Read(buffer, total, ReadSize)) == 0)
                        {
                            throw new ApplicationException();
                        }

                        total += read;
                        todo  += read;

                        // increment received bytes counter
                        _bytesReceived += read;

                        // do we need to check boundary ?
                        if ((boundaryLen != 0) && (!boundaryIsChecked))
                        {
                            // some IP cameras, like AirLink, claim that boundary is "myboundary",
                            // when it is really "--myboundary". this needs to be corrected.

                            pos = ByteArrayUtils.Find(buffer, boundary, 0, todo);
                            // continue reading if boudary was not found
                            if (pos == -1)
                            {
                                continue;
                            }

                            for (int i = pos - 1; i >= 0; i--)
                            {
                                byte ch = buffer[i];

                                if ((ch == (byte)'\n') || (ch == (byte)'\r'))
                                {
                                    break;
                                }

                                boudaryStr = (char)ch + boudaryStr;
                            }

                            boundary          = encoding.GetBytes(boudaryStr);
                            boundaryLen       = boundary.Length;
                            boundaryIsChecked = true;
                        }

                        // search for image start
                        if ((align == 1) && (todo >= jpegMagic.Length))
                        {
                            start = ByteArrayUtils.Find(buffer, jpegMagic, pos, todo);
                            if (start != -1)
                            {
                                // found JPEG start
                                pos   = start + jpegMagic.Length;
                                todo  = total - pos;
                                align = 2;
                            }
                            else
                            {
                                // delimiter not found
                                todo = jpegMagic.Length - 1;
                                pos  = total - todo;
                            }
                        }

                        // search for image end ( boundaryLen can be 0, so need extra check )
                        while ((align == 2) && (todo != 0) && (todo >= boundaryLen))
                        {
                            int stop = ByteArrayUtils.Find(buffer,
                                                           (boundaryLen != 0) ? boundary : jpegMagic,
                                                           pos, todo);

                            if (stop != -1)
                            {
                                // increment frames counter
                                _framesReceived++;

                                // image at stop
                                if ((NewFrame != null) && (!_stopEvent.WaitOne(0, false)))
                                {
                                    Bitmap bitmap;
                                    if (!String.IsNullOrEmpty(DecodeKey))
                                    {
                                        byte[] marker = Encoding.ASCII.GetBytes(DecodeKey);

                                        using (var ms = new MemoryStream(buffer, start + jpegMagic.Length, jpegMagic.Length + marker.Length))
                                        {
                                            var key = new byte[marker.Length];
                                            ms.Read(key, 0, marker.Length);

                                            if (!ByteArrayUtils.UnsafeCompare(marker, key))
                                            {
                                                throw (new Exception("Image Decode Failed - Check the decode key matches the encode key on ispy server"));
                                            }
                                        }


                                        using (var ms = new MemoryStream(buffer, start + marker.Length, stop - start - marker.Length))
                                        {
                                            ms.Seek(0, SeekOrigin.Begin);
                                            ms.WriteByte(jpegMagic[0]);
                                            ms.WriteByte(jpegMagic[1]);
                                            ms.WriteByte(jpegMagic[2]);
                                            ms.Seek(0, SeekOrigin.Begin);
                                            bitmap = (Bitmap)Image.FromStream(ms);
                                        }
                                    }
                                    else
                                    {
                                        using (var ms = new MemoryStream(buffer, start, stop - start))
                                        {
                                            bitmap = (Bitmap)Image.FromStream(ms);
                                        }
                                    }

                                    // notify client
                                    NewFrame(this, new NewFrameEventArgs(bitmap));
                                    // release the image
                                    bitmap.Dispose();
                                    bitmap = null;
                                }

                                // shift array
                                pos  = stop + boundaryLen;
                                todo = total - pos;
                                Array.Copy(buffer, pos, buffer, 0, todo);

                                total = todo;
                                pos   = 0;
                                align = 1;
                            }
                            else
                            {
                                // boundary not found
                                if (boundaryLen != 0)
                                {
                                    todo = boundaryLen - 1;
                                    pos  = total - todo;
                                }
                                else
                                {
                                    todo = 0;
                                    pos  = total;
                                }
                            }
                        }
                    }
                }
                catch (ApplicationException)
                {
                    // do nothing for Application Exception, which we raised on our own
                    // wait for a while before the next try
                    Thread.Sleep(250);
                }
                catch (ThreadAbortException)
                {
                    break;
                }
                catch (Exception exception)
                {
                    // provide information to clients
                    if (VideoSourceError != null)
                    {
                        VideoSourceError(this, new VideoSourceErrorEventArgs(exception.Message));
                    }
                    // wait for a while before the next try
                    Thread.Sleep(250);
                }
                finally
                {
                    // abort request
                    if (request != null)
                    {
                        try
                        {
                            request.Abort();
                        }
                        catch {}
                        request = null;
                    }
                    // close response stream
                    if (stream != null)
                    {
                        stream.Close();
                        stream = null;
                    }
                    // close response
                    if (response != null)
                    {
                        response.Close();
                        response = null;
                    }
                }

                // need to stop ?
                if (_stopEvent.WaitOne(0, false))
                {
                    break;
                }
            }

            if (PlayingFinished != null)
            {
                PlayingFinished(this, ReasonToFinishPlaying.StoppedByUser);
            }
        }