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相关推荐
- 录屏工具ScreenToGif功能总结
录屏工具ScreenToGif功能总结,以2.15.1为例,比之前版本新增很多功能. 下载地址: https://download.csdn.net/download/xianyu_padding/1 ...
- 用JS轻松实现一个录音、录像、录屏工具库
大家好,我是若川.持续组织了6个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...
- 实用分享-免费录屏工具(无水印)
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 windows录屏工具,Bandicam 工具下载路径:录屏工具免费版.zip-其它文档类资源- ...
- win7录屏_学用系列|清晰、体积小,这些录屏工具适合正在为录屏苦恼的你
2月10日,多家教学直播平台遭遇"教育双十一"的冲击,不少老师都感受到直播进不了课堂的苦,老师们不禁发出这样的困惑,直播那么难,我们可以录屏+视频网站发布吗?当然,不过,录屏软件那 ...
- android4.2屏幕录像,android——使用自带录屏工具进行屏幕录像
在做开源项目的时候,想传一个gif效果图上去.但是,要有连贯的动画效果.所以,就想到先录制视频,然后视频转gif.但是,用第三录屏软件总是不完美. 那么,怎么办呢? android4.4 提供了自带录 ...
- 屏幕录制大师哪款好用?这3款录屏工具,值得推荐!
案例:电脑录屏工具哪一款比较好用? [我一般用手机拍电脑上需要录制的内容,但是拍出来的视频画面小且不清晰.朋友说可以使用电脑录屏软件录制电脑屏幕,但我以前没有用过,不知道哪款好用?家人们有没有推荐的? ...
- 屏幕录像工具哪个好?这3款录屏工具就很不错!
案例:有没有好用的录屏工具分享? [每次对电脑屏幕进行录制都要花费我很多时间,录制的内容质量还差,真是事倍功半.听说使用好的录屏工具可以提高录屏的效率,那录屏软件哪款好用?在线蹲一款!] 在现代科技时 ...
- python录屏工具下载_Python移动端录屏库
Python移动端录屏库 背景 日常移动端专项测试和自动化测试通常有一些场景如:Ui自动化的操作捕获.App启动耗时.视频启播耗时等,通常都有需要边操作边录屏,而对于启动耗时测试通常还需要质量较高且帧 ...
- 3款免费好用的电脑录屏工具
案例:电脑录屏工具哪款免费又好用? "我想要挑选一款适合自己的好用的电脑录屏软件,但是我尝试了很多款录屏软件结果都不尽人意.免费版的软件功能少,录制效果差,想要高级功能需要付费解锁.想问问大 ...
- linux中录屏工具byzanz
linux中录屏工具byzanz: 1.安装 sudo apt install byzanz 2.使用 help:byzanz-record --help 配合xwininfo使用--xwininfo ...
最新文章
- centos下升级glib
- Expected a key while parsing a block mapping. assets: ^
- create_softLink.sh
- 详解 TCP 和 UDP
- Kafka 监控 Kafka Eagle 图形化版本
- HTML渐变背景不重复,如何停止重复自身的背景颜色渐变? (css)
- zynq中mgtx应用_【干货分享】ZYNQ常用外设设计 (上)
- 【LeetCode】Sum Root to Leaf Numbers
- 超过父控件的部分不能响应事件怎么办
- 西威变频器调试软件GF-EXprss
- 华为USG防火墙配置命令
- yytext table html,快速掌握YYText
- 74ls20设计半加器_组合逻辑电路(半加器全加器及逻辑运算)实验报告
- UNet++ 论文翻译
- qgc地面站如何导入离线地图_离线地图
- matlab单位函数定义,MATLAB 函数(一)
- Google Earth Engine ——QGIS中计算加权质心
- 桌面上程序可以用计算机打不开,我电脑桌面图标程序都打不开怎么办
- 阿里云视频点播功能使用
- 组播地址MAC的计算