123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- using AForge.Video;
- using AForge.Video.DirectShow;
- using Lennox.LibYuvSharp;
- using System;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Linq;
- using System.Threading;
- using Vinno.FIS.TRTCClient.Common.Enum;
- using Vinno.FIS.TRTCClient.Common.Log;
- namespace Vinno.FIS.TRTCClient.Captures
- {
- internal class AForgeCapturer
- {
- private readonly string _id;
- private readonly int _outputWidth;
- private readonly int _outputHeight;
- private readonly int _deviceWidth;
- private readonly int _deviceHeight;
- private int _actualWidthBeforeResize;
- private int _actualHeightBeforeResize;
- private TRTCImageFrameData _imageFrameData;
- private VideoCaptureDevice _videoCaptureDevice;
- private readonly ManualResetEvent _handlingImageEvent = new ManualResetEvent(true);
- private EnumLiveChannelCategory _liveChannelCategory;
- private Rectangle _imageRectangle;
- private bool _isCapturing;
- private Bitmap _cameraBitmap;
- private int _lastCaptureTime = 0;
- private int _fps;
- private EnumCaptureMode _captureMode;
- public int OutputWidth => _outputWidth;
- public int OutputHeight => _outputHeight;
- public string Id => _id;
- public bool IsCapturing => _isCapturing;
- public event EventHandler<TRTCImageFrameData> ImageFrameReceived;
- public AForgeCapturer(string id, int width, int height, int fps, EnumLiveChannelCategory liveChannelCategory, int deviceWidth, int deviceHeight)
- {
- _id = id;
- _outputWidth = width;
- _outputHeight = height;
- _deviceWidth = deviceWidth;
- _deviceHeight = deviceHeight;
- _fps = fps;
- _liveChannelCategory = liveChannelCategory;
- _captureMode = EnumCaptureMode.Normal;
- _imageFrameData = new TRTCImageFrameData(OutputWidth, OutputHeight);
- _imageRectangle = new Rectangle(0, 0, OutputWidth, OutputHeight);
- Logger.WriteLineInfo($"AForgeCapturer {_id}: Resolution:{width} {height} {liveChannelCategory}");
- }
- public void StartCapture()
- {
- if (_isCapturing)
- {
- Logger.WriteLineWarn($"AForgeCapturer {_id}: Has Been In Capturing!");
- return;
- }
- var videoFilterInfos = new FilterInfoCollection(FilterCategory.VideoInputDevice).OfType<FilterInfo>();
- var filterInfo = videoFilterInfos.FirstOrDefault(i => Id.Contains(i.MonikerString) || i.MonikerString.Contains(Id));
- if (filterInfo != null)
- {
- _videoCaptureDevice = new VideoCaptureDevice(filterInfo.MonikerString);
- if (_outputHeight == _deviceHeight && _outputWidth == _deviceWidth)
- {
- var capbility = _videoCaptureDevice.VideoCapabilities.FirstOrDefault(x => x.FrameSize.Width == OutputWidth && x.FrameSize.Height == OutputHeight);
- if (capbility != null)
- {
- _videoCaptureDevice.VideoResolution = capbility;
- _actualWidthBeforeResize = OutputWidth;
- _actualHeightBeforeResize = OutputHeight;
- _captureMode = EnumCaptureMode.Normal;
- }
- else
- {
- capbility = _videoCaptureDevice.VideoCapabilities.Where(x => x.FrameSize.Width >= OutputWidth && x.FrameSize.Height >= OutputHeight).OrderBy(x => x.FrameSize.Width).FirstOrDefault();
- if (capbility != null)
- {
- _videoCaptureDevice.VideoResolution = capbility;
- _imageRectangle.Width = capbility.FrameSize.Width; ;
- _imageRectangle.Height = capbility.FrameSize.Height;
- _actualWidthBeforeResize = capbility.FrameSize.Width;
- _actualHeightBeforeResize = capbility.FrameSize.Height;
- _captureMode = EnumCaptureMode.Unspecify;
- }
- else
- {
- Logger.WriteLineError($"AForgeCapturer {_id}:Start Capture Error,The camera can't meet the Output{OutputWidth}X{OutputHeight} and Device{_deviceWidth}X{_deviceHeight}!");
- return;
- }
- }
- }
- else
- {
- var capbility = _videoCaptureDevice.VideoCapabilities.FirstOrDefault(x => x.FrameSize.Width == _deviceWidth && x.FrameSize.Height == _deviceHeight);
- if (capbility != null)
- {
- _videoCaptureDevice.VideoResolution = capbility;
- _imageRectangle.Width = capbility.FrameSize.Width; ;
- _imageRectangle.Height = capbility.FrameSize.Height;
- _actualWidthBeforeResize = capbility.FrameSize.Width;
- _actualHeightBeforeResize = capbility.FrameSize.Height;
- _captureMode = EnumCaptureMode.Specify;
- }
- else
- {
- capbility = _videoCaptureDevice.VideoCapabilities.Where(x => x.FrameSize.Width >= OutputWidth && x.FrameSize.Height >= OutputHeight).OrderBy(x => x.FrameSize.Width).FirstOrDefault();
- if (capbility != null)
- {
- _videoCaptureDevice.VideoResolution = capbility;
- _imageRectangle.Width = capbility.FrameSize.Width; ;
- _imageRectangle.Height = capbility.FrameSize.Height;
- _actualWidthBeforeResize = capbility.FrameSize.Width;
- _actualHeightBeforeResize = capbility.FrameSize.Height;
- _captureMode = EnumCaptureMode.Unspecify;
- }
- else
- {
- Logger.WriteLineError($"AForgeCapturer {_id}:Start Capture Error,The camera can't meet the Output{OutputWidth}X{OutputHeight} and Device{_deviceWidth}X{_deviceHeight}!");
- return;
- }
- }
- }
- Logger.WriteLineInfo($"AForgeCapturer CaptureMode:{_captureMode},OutputWidth:{OutputWidth},OutputHeight:{OutputHeight},ActualWidthBeforeResize:{_actualWidthBeforeResize},ActualHeightBeforeResize:{_actualHeightBeforeResize}");
- _videoCaptureDevice.NewFrame += OnNewFrame;
- _videoCaptureDevice.Start();
- _isCapturing = true;
- Logger.WriteLineInfo($"AForgeCapturer {_id}: Start Capture!");
- return;
- }
- Logger.WriteLineError($"AForgeCapturer {_id}:Can not find device {_id},Start Capture Error!");
- }
- private void OnNewFrame(object sender, NewFrameEventArgs eventArgs)
- {
- try
- {
- _handlingImageEvent.Reset();
- if (Math.Abs(_lastCaptureTime - DateTime.Now.Millisecond) < 30)
- {
- return;
- }
- _lastCaptureTime = DateTime.Now.Millisecond;
- switch (_captureMode)
- {
- case EnumCaptureMode.Normal:
- using (var bitmap = eventArgs.Frame)
- {
- var bitmapData = bitmap.LockBits(_imageRectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- unsafe
- {
- Buffer.MemoryCopy(bitmapData.Scan0.ToPointer(), _imageFrameData.Data.ToPointer(), _imageFrameData.Size, _imageFrameData.Size);
- }
- bitmap.UnlockBits(bitmapData);
- }
- ImageFrameReceived?.Invoke(this, _imageFrameData);
- break;
- case EnumCaptureMode.Specify:
- ResizeBitmap(ref _cameraBitmap, _deviceWidth, _deviceHeight);
- using (eventArgs.Frame)
- {
- using (Graphics g = Graphics.FromImage(_cameraBitmap))
- {
- g.DrawImage(eventArgs.Frame, 0, 0, _deviceWidth, _deviceHeight);
- }
- var bitmapData = _cameraBitmap.LockBits(_imageRectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- unsafe
- {
- var captureData = (byte*)bitmapData.Scan0.ToPointer();
- var tempData = (byte*)_imageFrameData.Data.ToPointer();
- LibYuv.ARGBScale(captureData, _deviceWidth * 4, _deviceWidth, _deviceHeight, tempData, OutputWidth * 4, OutputWidth, OutputHeight, FilterMode.None);
- }
- _cameraBitmap.UnlockBits(bitmapData);
- ImageFrameReceived?.Invoke(this, _imageFrameData);
- }
- break;
- case EnumCaptureMode.Unspecify:
- ResizeBitmap(ref _cameraBitmap, _actualWidthBeforeResize, _actualHeightBeforeResize);
- using (eventArgs.Frame)
- {
- using (Graphics g = Graphics.FromImage(_cameraBitmap))
- {
- g.DrawImage(eventArgs.Frame, 0, 0, _actualWidthBeforeResize, _actualHeightBeforeResize);
- }
- var bitmapData = _cameraBitmap.LockBits(_imageRectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- unsafe
- {
- var captureData = (byte*)bitmapData.Scan0.ToPointer();
- var tempData = (byte*)_imageFrameData.Data.ToPointer();
- LibYuv.ARGBScale(captureData, _actualWidthBeforeResize * 4, _actualWidthBeforeResize, _actualHeightBeforeResize, tempData, OutputWidth * 4, OutputWidth, OutputHeight, FilterMode.None);
- }
- _cameraBitmap.UnlockBits(bitmapData);
- ImageFrameReceived?.Invoke(this, _imageFrameData);
- }
- break;
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"AForgeCapturer {Id} receive data error:{ex}");
- }
- finally
- {
- _handlingImageEvent.Set();
- }
- }
- public void StopCapture()
- {
- try
- {
- if (_isCapturing)
- {
- if (_videoCaptureDevice != null)
- {
- _videoCaptureDevice.NewFrame -= OnNewFrame;
- if (_videoCaptureDevice.IsRunning)
- {
- var stopThread = new Thread(() =>
- {
- try
- {
- _videoCaptureDevice.SignalToStop();
- _videoCaptureDevice.WaitForStop();
- }
- catch
- {
- }
- });
- stopThread.Start();
- try
- {
- if (!stopThread.Join(2000))
- {
- stopThread.Abort();
- }
- }
- catch
- {
- }
- }
- _videoCaptureDevice = null;
- }
- _isCapturing = false;
- Logger.WriteLineInfo($"AForgeCapturer {_id}: Stop Capture!");
- }
- }
- catch (Exception e)
- {
- Logger.WriteLineError($"AForgeCapturer {_id}:Stop Capture Error:{e}");
- }
- }
- public void Dispose()
- {
- StopCapture();
- _handlingImageEvent.WaitOne();
- _imageFrameData?.Dispose();
- _cameraBitmap?.Dispose();
- }
- private void ResizeBitmap(ref Bitmap bitmap, int width, int height)
- {
- if (bitmap == null)
- {
- bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
- }
- else if (bitmap.Width != width || bitmap.Height != height)
- {
- bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
- }
- }
- }
- }
|