private void WorkerThread() { int width = region.Width; int height = region.Height; int x = region.Location.X; int y = region.Location.Y; Size size = region.Size; Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(bitmap); DateTime start; TimeSpan span; while (!stopEvent.WaitOne(0, false)) { start = DateTime.Now; try { graphics.CopyFromScreen(x, y, 0, 0, size, CopyPixelOperation.SourceCopy); framesReceived++; NewFrame?.Invoke(this, new NewFrameEventArgs(bitmap)); if (frameInterval > 0) { span = DateTime.Now.Subtract(start); int msec = frameInterval - (int)span.TotalMilliseconds; if ((msec > 0) && (stopEvent.WaitOne(msec, false))) { break; } } } catch (ThreadAbortException) { break; } catch (Exception exception) { VideoSourceError?.Invoke(this, new VideoSourceErrorEventArgs(exception.Message)); Thread.Sleep(250); } if (stopEvent.WaitOne(0, false)) { break; } } graphics.Dispose(); bitmap.Dispose(); PlayingFinished?.Invoke(this, ReasonToFinishPlaying.StoppedByUser); }
private async Task ProcessVideoAsync(CancellationToken token) { await Task.Yield(); try { using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { await Task.Factory.FromAsync(clientSocket.BeginConnect, clientSocket.EndConnect, $"roborio-{teamNumber}-FRC.local", CameraServerPort, null); using (var socketStream = new NetworkStream(clientSocket)) { await socketStream.WriteAsync(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(framesPerSecond)), 0, 4, token); bytesReceived += 4; await socketStream.WriteAsync(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(HwCompressionId)), 0, 4, token); bytesReceived += 4; await socketStream.WriteAsync(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size640x480)), 0, 4, token); bytesReceived += 4; while (true) { token.ThrowIfCancellationRequested(); var magicToken = new byte[4]; await socketStream.ReadAsync(magicToken, 0, 4, token); bytesReceived += 4; if (BitConverter.ToInt32(magicToken, 0) != 0x1000) { //Magic token did not match return; } var imageLengthBytes = new byte[4]; await socketStream.ReadAsync(imageLengthBytes, 0, 4, token); bytesReceived += 4; using (var frame = new System.Drawing.Bitmap(socketStream)) { NewFrame?.Invoke(this, new NewFrameEventArgs(frame)); } bytesReceived += IPAddress.NetworkToHostOrder(BitConverter.ToInt32(imageLengthBytes, 0)); framesReceived++; } } } } catch (OperationCanceledException) { PlayingFinished?.Invoke(this, ReasonToFinishPlaying.StoppedByUser); } catch (Exception ex) { PlayingFinished?.Invoke(this, ReasonToFinishPlaying.VideoSourceError); VideoSourceError?.Invoke(this, new VideoSourceErrorEventArgs(ex.Message)); } }
/// <summary> /// Worker thread. /// </summary> /// private void WorkerThread() { ReasonToFinishPlaying reasonToStop = ReasonToFinishPlaying.StoppedByUser; try { // run mediaControl.Run(); while (!stopEvent.WaitOne(0, true)) { Thread.Sleep(100); if (mediaEvent != null) { if (mediaEvent.GetEvent(out DsEvCode code, out IntPtr p1, out IntPtr p2, 0) >= 0) { mediaEvent.FreeEventParams(code, p1, p2); if (code == DsEvCode.Complete) { reasonToStop = ReasonToFinishPlaying.EndOfStreamReached; break; } } } } mediaControl.StopWhenReady(); } catch (Exception exception) { // provide information to clients VideoSourceError?.Invoke(this, new VideoSourceErrorEventArgs(exception.Message)); } finally { DestroyFilters(); } PlayingFinished?.Invoke(this, reasonToStop); }
private void CreateFilters() { isValid = true; // grabber grabberVideo = new GrabberVideo(this); grabberAudio = new GrabberAudio(this); // objects graphObject = null; grabberObjectVideo = null; grabberObjectAudio = null; int sourceBaseVideoPinIndex = 0; try { // get type for filter graph Type type = Type.GetTypeFromCLSID(Clsid.FilterGraph); if (type == null) { throw new ApplicationException("Failed creating filter graph"); } // create filter graph graphObject = Activator.CreateInstance(type); graph = (IGraphBuilder)graphObject; // create source device's object if (fileName.ToLower().EndsWith(".wmv")) { type = Type.GetTypeFromCLSID(Clsid.WMASFReader); if (type == null) { throw new ApplicationException("Failed creating ASF Reader filter"); } sourceBase = (IBaseFilter)Activator.CreateInstance(type); IFileSourceFilter sourceFile = (IFileSourceFilter)sourceBase; sourceFile.Load(fileName, null); graph.AddFilter(sourceBase, "source"); sourceBaseVideoPinIndex = 1; } else { graph.AddSourceFilter(fileName, "source", out sourceBase); if (sourceBase == null) { try { type = Type.GetTypeFromCLSID(Clsid.AsyncReader); if (type == null) { throw new ApplicationException("Failed creating Async Reader filter"); } sourceBase = (IBaseFilter)Activator.CreateInstance(type); IFileSourceFilter sourceFile = (IFileSourceFilter)sourceBase; sourceFile.Load(fileName, null); graph.AddFilter(sourceBase, "source"); } catch { throw new ApplicationException("Failed creating source filter"); } } sourceBaseVideoPinIndex = 0; } // get type for sample grabber type = Type.GetTypeFromCLSID(Clsid.SampleGrabber); if (type == null) { throw new ApplicationException("Failed creating sample grabber"); } // create sample grabber grabberObjectVideo = Activator.CreateInstance(type); sampleGrabberVideo = (ISampleGrabber)grabberObjectVideo; grabberBaseVideo = (IBaseFilter)grabberObjectVideo; // add grabber filters to graph graph.AddFilter(grabberBaseVideo, "grabberVideo"); // set media type AMMediaType mediaType = new AMMediaType { MajorType = MediaType.Video, SubType = MediaSubType.ARGB32 /* MediaSubType.RGB24 */ }; ; sampleGrabberVideo.SetMediaType(mediaType); // connect pins IPin outPin = Tools.GetOutPin(sourceBase, sourceBaseVideoPinIndex); IPin inPin = Tools.GetInPin(grabberBaseVideo, 0); if (graph.Connect(outPin, inPin) < 0) { throw new ApplicationException("Failed connecting sourceBase to grabberBaseVideo"); } Marshal.ReleaseComObject(outPin); Marshal.ReleaseComObject(inPin); // get media type if (sampleGrabberVideo.GetConnectedMediaType(mediaType) == 0) { VideoInfoHeader vih = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.FormatPtr, typeof(VideoInfoHeader)); grabberVideo.Width = vih.BmiHeader.Width; grabberVideo.Height = vih.BmiHeader.Height; mediaType.Dispose(); } if (useAudioGrabber) { // ***************************************************************** // ******** Add the audio grabber to monitor audio peaks *********** bool audioGrabberIsConnected = false; Tools.FilterInfo2 filterInfo2 = Tools.GetNextFilter(sourceBase, PinDirection.Output, 0); foreach (Tools.PinInfo2 pinInfo2 in filterInfo2.Pins) { if (pinInfo2.PinInfo.Direction == PinDirection.Output) { if (!Tools.IsPinConnected(pinInfo2.Pin)) { try { graph.Render(pinInfo2.Pin); AMMediaType mt = new AMMediaType(); pinInfo2.Pin.ConnectionMediaType(mt); if (mt.MajorType == MediaType.Audio) { // Obtain a reference to the filter connected to the audio output of the video splitter (usually, this is the audio decoder) Tools.FilterInfo2 decoderFilterInfo2 = Tools.GetNextFilter(pinInfo2.PinInfo.Filter, PinDirection.Output, 0); // Remove all the filters connected to the audio decoder filter System.Collections.Generic.List <Tools.FilterInfo2> filtersInfo2 = new System.Collections.Generic.List <Tools.FilterInfo2>(); Tools.FilterInfo2 testFilterInfo2 = Tools.GetNextFilter(decoderFilterInfo2.Filter, PinDirection.Output, 0); while (true) { filtersInfo2.Add(testFilterInfo2); testFilterInfo2 = Tools.GetNextFilter(testFilterInfo2.Filter, PinDirection.Output, 0); if (testFilterInfo2.Filter == null) { break; } } foreach (Tools.FilterInfo2 fi2 in filtersInfo2) { graph.RemoveFilter(fi2.Filter); fi2.Release(); } // get type for sample grabber type = Type.GetTypeFromCLSID(Clsid.SampleGrabber); if (type == null) { throw new ApplicationException("Failed creating audio sample grabber"); } // create sample grabber grabberObjectAudio = Activator.CreateInstance(type); sampleGrabberAudio = (ISampleGrabber)grabberObjectAudio; grabberBaseAudio = (IBaseFilter)grabberObjectAudio; // add grabber filters to graph graph.AddFilter(grabberBaseAudio, "grabberAudio"); // set media type AMMediaType mediaTypeAudio = new AMMediaType { MajorType = MediaType.Audio, SubType = MediaSubType.PCM, FormatType = FormatType.WaveEx }; sampleGrabberAudio.SetMediaType(mediaTypeAudio); outPin = Tools.GetOutPin(decoderFilterInfo2.Filter, 0); inPin = Tools.GetInPin(grabberBaseAudio, 0); if (graph.Connect(outPin, inPin) < 0) { throw new ApplicationException("Failed connecting filter to grabberBaseAudio"); } Marshal.ReleaseComObject(outPin); Marshal.ReleaseComObject(inPin); // Finally, connect the grabber to the audio renderer outPin = Tools.GetOutPin(grabberBaseAudio, 0); graph.Render(outPin); mt = new AMMediaType(); outPin.ConnectionMediaType(mt); if (!Tools.IsPinConnected(outPin)) { throw new ApplicationException("Failed obtaining media audio information"); } wavFormat = new WaveFormatEx(); Marshal.PtrToStructure(mt.FormatPtr, wavFormat); Marshal.ReleaseComObject(outPin); // configure sample grabber sampleGrabberAudio.SetBufferSamples(false); sampleGrabberAudio.SetOneShot(false); sampleGrabberAudio.SetCallback(grabberAudio, 1); audioGrabberIsConnected = true; break; } } catch { } } } } filterInfo2.Release(); if (!audioGrabberIsConnected) { foreach (Tools.PinInfo2 pinInfo2 in Tools.GetPins(sourceBase)) { if (!Tools.IsPinConnected(pinInfo2.Pin)) { foreach (AMMediaType mt in Tools.GetMediaTypes(pinInfo2.Pin)) { if (mt.MajorType == MediaType.Audio) { // create sample grabber grabberObjectAudio = Activator.CreateInstance(type); sampleGrabberAudio = (ISampleGrabber)grabberObjectAudio; grabberBaseAudio = (IBaseFilter)grabberObjectAudio; // add grabber filters to graph graph.AddFilter(grabberBaseAudio, "grabberAudio"); // set media type AMMediaType mediaTypeAudio = new AMMediaType { MajorType = MediaType.Audio, SubType = MediaSubType.PCM, FormatType = FormatType.WaveEx }; sampleGrabberAudio.SetMediaType(mediaTypeAudio); inPin = Tools.GetInPin(grabberBaseAudio, 0); if (graph.Connect(pinInfo2.Pin, inPin) < 0) { throw new ApplicationException("Failed connecting sourceBase to grabberBaseVideo"); } Marshal.ReleaseComObject(inPin); // Finally, connect the grabber to the audio renderer outPin = Tools.GetOutPin(grabberBaseAudio, 0); graph.Render(outPin); AMMediaType amt = new AMMediaType(); outPin.ConnectionMediaType(amt); if (!Tools.IsPinConnected(outPin)) { throw new ApplicationException("Failed obtaining media audio information"); } wavFormat = new WaveFormatEx(); Marshal.PtrToStructure(amt.FormatPtr, wavFormat); Marshal.ReleaseComObject(outPin); // configure sample grabber sampleGrabberAudio.SetBufferSamples(false); sampleGrabberAudio.SetOneShot(false); sampleGrabberAudio.SetCallback(grabberAudio, 1); audioGrabberIsConnected = true; break; } } } } } // ***************************************************************** } // let's do the rendering, if we don't need to prevent freezing if (!preventFreezing) { // render pin graph.Render(Tools.GetOutPin(grabberBaseVideo, 0)); // configure video window IVideoWindow window = (IVideoWindow)graphObject; window.put_AutoShow(false); window = null; } // configure sample grabber sampleGrabberVideo.SetBufferSamples(false); sampleGrabberVideo.SetOneShot(false); sampleGrabberVideo.SetCallback(grabberVideo, 1); // disable clock, if someone requested it if (!referenceClockEnabled) { IMediaFilter mediaFilter = (IMediaFilter)graphObject; mediaFilter.SetSyncSource(null); } // get media control mediaControl = (IMediaControl)graphObject; // get media seek control mediaSeekControl = (IMediaSeeking)graphObject; // get media events' interface mediaEvent = (IMediaEventEx)graphObject; // get media audio control basicAudio = (IBasicAudio)graphObject; } catch (Exception exception) { DestroyFilters(); // provide information to clients VideoSourceError?.Invoke(this, new VideoSourceErrorEventArgs(exception.Message)); } }
// Worker thread 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 (HttpUserAgent != null) { request.UserAgent = HttpUserAgent; } // 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 (SeparateConnectionGroup) { 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))) { var frame = new byte[stop - start]; Array.Copy(buffer, start, frame, 0, stop - start); NewFrame(frame); } // 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 VideoSourceError?.Invoke(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; } } PlayingFinished?.Invoke(ReasonToFinishPlaying.StoppedByUser); }