Github每日精选(第16期):录屏工具ScreenToGif
生活随笔
收集整理的這篇文章主要介紹了
Github每日精选(第16期):录屏工具ScreenToGif
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ScreenToGif
ScreenToGif允許您記錄屏幕的選定區域、網絡攝像頭的實時信息或素描板上的實時繪圖。之后,您可以編輯動畫并將其保存為 gif、apng、視頻、psd 或 png 圖像。
ScreenToGif在github下的地址在這里。
功能介紹:
-
1.記錄你的屏幕,并直接保存到一個GIF動畫的環形。
-
2.暫停和繼續記錄。
-
3.移動窗口來記錄你想要的。
-
4.您可以添加文字,字幕和標題框。
-
5.編輯框,添加過濾器,還原,做優悠風格,斯洛伐克運動,加邊框。
-
6.導出幀。
-
7.作物和調整。
-
8.你可以工作,即使在節目錄制。
-
9.刪除你不想要的幀。
-
10.選擇一個文件夾,自動保存文件或選擇一個enconding之前。
ScreenToGif也比較簡單,主要的有兩個功能,一個是錄取屏幕一個是錄取攝像頭的視頻。
還有一個白板的功能,也是挺好玩的:
主要代碼分析
獲取攝像頭的數據:
protected void CreateGraph(){//Skip if already createdif ((int)ActualGraphState < (int)GraphState.Created){//Make a new filter graph.GraphBuilder = (ExtendStreaming.IGraphBuilder)Activator.CreateInstance(Type.GetTypeFromCLSID(Uuid.Clsid.FilterGraph, true));//Get the Capture Graph Builder.var clsid = Uuid.Clsid.CaptureGraphBuilder2;var riid = typeof(ExtendStreaming.ICaptureGraphBuilder2).GUID;CaptureGraphBuilder = (ExtendStreaming.ICaptureGraphBuilder2)Activator.CreateInstance(Type.GetTypeFromCLSID(clsid, true));//Link the CaptureGraphBuilder to the filter graphvar hr = CaptureGraphBuilder.SetFiltergraph(GraphBuilder);if (hr < 0)Marshal.ThrowExceptionForHR(hr);var comType = Type.GetTypeFromCLSID(Uuid.Clsid.SampleGrabber);if (comType == null)throw new Exception("DirectShow SampleGrabber not installed/registered!");var comObj = Activator.CreateInstance(comType);SampGrabber = (EditStreaming.ISampleGrabber)comObj; comObj = null;_baseGrabFlt = (CoreStreaming.IBaseFilter) SampGrabber;var media = new CoreStreaming.AmMediaType();//Get the video device and add it to the filter graphif (VideoDevice != null){VideoDeviceFilter = (CoreStreaming.IBaseFilter)Marshal.BindToMoniker(VideoDevice.MonikerString);hr = GraphBuilder.AddFilter(VideoDeviceFilter, "Video Capture Device");if (hr < 0)Marshal.ThrowExceptionForHR(hr);media.majorType = Uuid.MediaType.Video;media.subType = Uuid.MediaSubType.RGB32;//RGB24;media.formatType = Uuid.FormatType.VideoInfo;media.temporalCompression = true; //Newhr = SampGrabber.SetMediaType(media);if (hr < 0)Marshal.ThrowExceptionForHR(hr);hr = GraphBuilder.AddFilter(_baseGrabFlt, "Grabber");if (hr < 0)Marshal.ThrowExceptionForHR(hr);}// Retrieve the stream control interface for the video device// FindInterface will also add any required filters// (WDM devices in particular may need additional// upstream filters to function).// Try looking for an interleaved media typeobject o;var cat = Uuid.PinCategory.Capture;var med = Uuid.MediaType.Interleaved;var iid = typeof(ExtendStreaming.IAMStreamConfig).GUID;hr = CaptureGraphBuilder.FindInterface(cat, med, VideoDeviceFilter, iid, out o);if (hr != 0){// If not found, try looking for a video media typemed = Uuid.MediaType.Video;hr = CaptureGraphBuilder.FindInterface(cat, med, VideoDeviceFilter, iid, out o);if (hr != 0)o = null;}VideoStreamConfig = o as ExtendStreaming.IAMStreamConfig;// Retrieve the media control interface (for starting/stopping graph)MediaControl = (ControlStreaming.IMediaControl)GraphBuilder;// Reload any video crossbars//if (videoSources != null) videoSources.Dispose(); videoSources = null;_videoInfoHeader = (EditStreaming.VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(EditStreaming.VideoInfoHeader));Marshal.FreeCoTaskMem(media.formatPtr); media.formatPtr = IntPtr.Zero;hr = SampGrabber.SetBufferSamples(false);if (hr == 0)hr = SampGrabber.SetOneShot(false);if (hr == 0)hr = SampGrabber.SetCallback(null, 0);if (hr < 0)Marshal.ThrowExceptionForHR(hr);}//Update the state now that we are done.ActualGraphState = GraphState.Created;}每一幀的數據:
public Bitmap GetFrame(){//TODO: Verify any possible leaks.//Asks for the buffer size.var bufferSize = 0;SampGrabber.GetCurrentBuffer(ref bufferSize, IntPtr.Zero);//Allocs the byte array.var handleObj = GCHandle.Alloc(_savedArray, GCHandleType.Pinned);//Gets the address of the pinned object.var address = handleObj.AddrOfPinnedObject();//Puts the buffer inside the byte array.SampGrabber.GetCurrentBuffer(ref bufferSize, address);//Image size.var width = _videoInfoHeader.BmiHeader.Width;var height = _videoInfoHeader.BmiHeader.Height;var stride = width * 3;//address += (height - 1) * stride;address += height * stride;var bitmap = new Bitmap(width, height, -stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, address);handleObj.Free();return bitmap;}截取屏幕:
public override int Capture(FrameInfo frame){var res = new Result(-1);var wasCaptured = false;try{//Try to get the duplicated output frame within given time.res = DuplicatedOutput.TryAcquireNextFrame(0, out var info, out var resource);if (res.Failure || resource == null || info.TotalMetadataBufferSize == 0){//Somehow, it was not possible to retrieve the resource, frame or metadata.resource?.Dispose();return FrameCount;}#region Process changes//Copy resource into memory that can be accessed by the CPU.using (var screenTexture = resource.QueryInterface<Texture2D>()){#region Moved rectanglesvar movedRectangles = new OutputDuplicateMoveRectangle[info.TotalMetadataBufferSize];DuplicatedOutput.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out var movedRegionsLength);for (var movedIndex = 0; movedIndex < movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle)); movedIndex++){//Crop the destination rectangle to the scree area rectangle.var left = Math.Max(movedRectangles[movedIndex].DestinationRect.Left, Left);var right = Math.Min(movedRectangles[movedIndex].DestinationRect.Right, Left + Width);var top = Math.Max(movedRectangles[movedIndex].DestinationRect.Top, Top);var bottom = Math.Min(movedRectangles[movedIndex].DestinationRect.Bottom, Top + Height);//Copies from the screen texture only the area which the user wants to capture.if (right > left && bottom > top){//Limit the source rectangle to the available size within the destination rectangle.var sourceWidth = movedRectangles[movedIndex].SourcePoint.X + (right - left);var sourceHeight = movedRectangles[movedIndex].SourcePoint.Y + (bottom - top);Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, new ResourceRegion(movedRectangles[movedIndex].SourcePoint.X, movedRectangles[movedIndex].SourcePoint.Y, 0, sourceWidth, sourceHeight, 1),StagingTexture, 0, left - Left, top - Top);wasCaptured = true;}}#endregion#region Dirty rectanglesvar dirtyRectangles = new RawRectangle[info.TotalMetadataBufferSize];DuplicatedOutput.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out var dirtyRegionsLength);for (var dirtyIndex = 0; dirtyIndex < dirtyRegionsLength / Marshal.SizeOf(typeof(RawRectangle)); dirtyIndex++){//Crop screen positions and size to frame sizes.var left = Math.Max(dirtyRectangles[dirtyIndex].Left, Left);var right = Math.Min(dirtyRectangles[dirtyIndex].Right, Left + Width);var top = Math.Max(dirtyRectangles[dirtyIndex].Top, Top);var bottom = Math.Min(dirtyRectangles[dirtyIndex].Bottom, Top + Height);//Copies from the screen texture only the area which the user wants to capture.if (right > left && bottom > top){Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, new ResourceRegion(left, top, 0, right, bottom, 1), StagingTexture, 0, left - Left, top - Top);wasCaptured = true;}}#endregionif (!wasCaptured){//Nothing was changed within the capture region, so ignore this frame.resource.Dispose();return FrameCount;}}#endregion#region Gets the image data//Gets the staging texture as a stream.var data = Device.ImmediateContext.MapSubresource(StagingTexture, 0, MapMode.Read, MapFlags.None);if (data.IsEmpty){Device.ImmediateContext.UnmapSubresource(StagingTexture, 0);resource?.Dispose();return FrameCount;}var bitmap = new System.Drawing.Bitmap(Width, Height, PixelFormat.Format32bppArgb);var boundsRect = new System.Drawing.Rectangle(0, 0, Width, Height);//Copy pixels from screen capture Texture to the GDI bitmap.var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);var sourcePtr = data.DataPointer;var destPtr = mapDest.Scan0;for (var y = 0; y < Height; y++){//Copy a single line.Utilities.CopyMemory(destPtr, sourcePtr, Width * 4);//Advance pointers.sourcePtr = IntPtr.Add(sourcePtr, data.RowPitch);destPtr = IntPtr.Add(destPtr, mapDest.Stride);}//Release source and dest locks.bitmap.UnlockBits(mapDest);//Set frame details.FrameCount++;frame.Path = $"{Project.FullPath}{FrameCount}.png";frame.Delay = FrameRate.GetMilliseconds();frame.Image = bitmap;BlockingCollection.Add(frame);#endregionDevice.ImmediateContext.UnmapSubresource(StagingTexture, 0);resource?.Dispose();return FrameCount;}catch (SharpDXException se) when (se.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code){return FrameCount;}catch (SharpDXException se) when (se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceRemoved.Result.Code || se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceReset.Result.Code){//When the device gets lost or reset, the resources should be instantiated again.DisposeInternal();Initialize();return FrameCount;}catch (Exception ex){LogWriter.Log(ex, "It was not possible to finish capturing the frame with DirectX.");OnError.Invoke(ex);return FrameCount;}finally{try{//Only release the frame if there was a success in capturing it.if (res.Success)DuplicatedOutput.ReleaseFrame();}catch (Exception e){LogWriter.Log(e, "It was not possible to release the frame.");}}}白板數據:
定時獲取白板內容:
private void Normal_Elapsed(object sender, EventArgs e){var fileName = $"{Project.FullPath}{FrameCount}.png";//TODO: GetRender fails to create useful image when the control has decimals values as size.var render = MainBorder.GetRender(_dpi); //TODO: Too heavy! Maybe just save the strokes? like layers?Project.Frames.Add(new FrameInfo(fileName, FrameRate.GetMilliseconds()));ThreadPool.QueueUserWorkItem(delegate { AddFrames(fileName, render); });FrameCount++;}數據加入每一幀中:
private void AddFrames(string fileName, BitmapSource bitmap){//var mutexLock = new Mutex(false, bitmap.GetHashCode().ToString());//mutexLock.WaitOne();using (var stream = new FileStream(fileName, FileMode.Create)){var encoder = new PngBitmapEncoder();encoder.Frames.Add(BitmapFrame.Create(bitmap));encoder.Save(stream);stream.Flush();stream.Close();}//GC.Collect(1);//mutexLock.ReleaseMutex();}總結
以上是生活随笔為你收集整理的Github每日精选(第16期):录屏工具ScreenToGif的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JSON 的几种简单格式和转换
- 下一篇: javaWeb图书购物商城