AForge.Video.MJPEGStream.WorkerThread C# (CSharp) Method

WorkerThread() private method

private WorkerThread ( ) : void
return void
		private void WorkerThread( )
		{
			// buffer to read stream
			byte[] buffer = new byte[bufSize];
			// JPEG magic number
			byte[] jpegMagic = new byte[] { 0xFF, 0xD8, 0xFF };
			int jpegMagicLength = 3;

			ASCIIEncoding 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 = null;
				string boudaryStr = null;
				// length of boundary
				int boundaryLen;
				// flag signaling if boundary was checked or not
				bool boundaryIsChecked = false;
				// read amounts and positions
				int read, todo = 0, total = 0, pos = 0, align = 1;
				int start = 0, stop = 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;
					}

					// set timeout value for the request
					request.Timeout = requestTimeout;
					// 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
					if ( forceBasicAuthentication )
					{
						string authInfo = string.Format( "{0}:{1}", login, password );
						authInfo = Convert.ToBase64String( Encoding.Default.GetBytes( authInfo ) );
						request.Headers["Authorization"] = "Basic " + authInfo;
					}
					// get response
					response = request.GetResponse( );

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

					// "application/octet-stream"
					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
						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 >= jpegMagicLength ) )
						{
							start = ByteArrayUtils.Find( buffer, jpegMagic, pos, todo );
							if ( start != -1 )
							{
								// found JPEG start
								pos		= start + jpegMagicLength;
								todo	= total - pos;
								align	= 2;
							}
							else
							{
								// delimiter not found
								todo    = jpegMagicLength - 1;
								pos		= total - todo;
							}
						}

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

							if ( stop != -1 )
							{
								pos		= stop;
								todo	= total - pos;

								// increment frames counter
								framesReceived ++;

								// image at stop
								if ( ( NewFrame != null ) && ( !stopEvent.WaitOne( 0, false ) ) )
								{
									System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(new MemoryStream(buffer, start, stop - start));
									// 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)
					{
						request.Abort( );
						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 );
			}
		}
	}