programing

Windows에서 가장 빠른 화면 캡처 방법

randomtip 2022. 10. 12. 21:21
반응형

Windows에서 가장 빠른 화면 캡처 방법

Windows 플랫폼용 스크린캐스팅 프로그램을 작성하려고 하는데 화면을 캡처하는 방법을 알 수 없습니다.제가 알고 있는 유일한 방법은 GDI를 사용하는 것입니다만, 다른 방법이 있는지, 있다면 가장 적은 오버헤드를 초래하는 방법은 무엇입니까?속도가 우선입니다.

스크린캐스팅 프로그램은 게임 장면을 녹화하기 위한 프로그램이지만, 만약 이것이 선택지를 좁힌다면, 저는 여전히 이 범위에 포함되지 않는 다른 제안들을 받아들일 준비가 되어 있습니다.결국 지식은 나쁘지 않다.

편집: 우연히 본 기사:화면을 캡처하기 위한 다양한 방법.Windows Media API의 방법과 DirectX의 방법을 소개했습니다.결론에서 하드웨어 액셀러레이션을 비활성화하면 캡처 애플리케이션의 성능이 대폭 향상될 수 있다고 언급하고 있습니다.이게 왜 그런지 궁금해요.빠진 빈칸을 채워줄 사람 있나요?

편집: Camtasia와 같은 스크린캐스팅 프로그램이 자체 캡처 드라이버를 사용한다고 읽었습니다.누가 어떻게 작동하는지, 왜 더 빠른지 자세히 설명해 주실 수 있나요?저도 그런 것을 실장하기 위한 가이던스가 필요할지도 모릅니다만, 어쨌든 기존의 문서는 있을 것입니다.

또한 FRAPS가 어떻게 화면을 녹화하는지 알게 되었습니다.기본 그래픽 API를 후크하여 백버퍼에서 읽습니다.비디오 RAM이 아닌 시스템 RAM에서 읽기 때문에 전면 버퍼에서 읽기보다 빠른 것으로 알고 있습니다.여기서 기사를 읽으실 수 있습니다.

편집: 첫 번째 편집 링크 아래에 "GDI 방식"으로 나열되어 있습니다.그 사이트에서는 퍼포먼스 어드바이저리라고 해도, 30fps까지는 간단하게 할 수 있다고 생각합니다.

코멘트에서 (저는 이 작업을 해본 경험이 없습니다.그냥 하고 있는 사람을 언급하고 있습니다)

HDC hdc = GetDC(NULL); // get the desktop device context
HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself

// get the height and width of the screen
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);

// create a bitmap
HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height);

// use the previously created device context with the bitmap
SelectObject(hDest, hbDesktop);

// copy from the desktop device context to the bitmap device context
// call this once per 'frame'
BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY);

// after the recording is done, release the desktop context you got..
ReleaseDC(NULL, hdc);

// ..delete the bitmap you were using to capture frames..
DeleteObject(hbDesktop);

// ..and delete the context you created
DeleteDC(hDest);

빠르다고 건 요, 이 은요.BitBlt호환성이 있는 디바이스 컨텍스트간에 카피하는 경우는, 통상은 매우 고속입니다.

참고로 Open Broadcaster Software는 수신처 컨텍스트를 작성하는 것이 아니라 "dc_capture" 메서드의 일부로 이와 같은 기능을 구현합니다.hDest를 사용합니다.CreateCompatibleDCDirectX 10+에서 동작하는를 사용합니다.이에 대한 지원이 없을 경우 다음 단계로 넘어갑니다.CreateCompatibleDC.

하기 위해 첫을 '어울리다'로 .GetDC(game)서 ''는game을 맞춥니다. 이치노height ★★★★★★★★★★★★★★★★★」width게임 창구도 있어요

일단 hDest/hbDesktop에 픽셀이 있으면 여전히 파일에 저장해야 하는데, 화면 캡처를 할 경우 일정 개수의 픽셀을 메모리에 버퍼링하고 비디오 파일에 청크로 저장해야 한다고 생각하기 때문에 정적 이미지를 디스크에 저장하는 코드를 가리키지 않습니다.

이것은 단일 프레임을 수집할 때 사용하는 것입니다만, 이것을 수정해, 2개의 타겟을 항상 열어 두면, 파일명의 정적 카운터를 사용해 디스크에 「스트리밍」할 수 있습니다.-이것을 어디서 찾았는지는 기억나지 않지만, 누구 덕분입니다.

void dump_buffer()
{
   IDirect3DSurface9* pRenderTarget=NULL;
   IDirect3DSurface9* pDestTarget=NULL;
     const char file[] = "Pickture.bmp";
   // sanity checks.
   if (Device == NULL)
      return;

   // get the render target surface.
   HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget);
   // get the current adapter display mode.
   //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

   // create a destination surface.
   hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width,
                         DisplayMde.Height,
                         DisplayMde.Format,
                         D3DPOOL_SYSTEMMEM,
                         &pDestTarget,
                         NULL);
   //copy the render target to the destination surface.
   hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget);
   //save its contents to a bitmap file.
   hr = D3DXSaveSurfaceToFile(file,
                              D3DXIFF_BMP,
                              pDestTarget,
                              NULL,
                              NULL);

   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();
}

DirectX 어플리케이션용 FRAPS와 같은 비디오 캡처 소프트웨어를 작성했습니다.소스코드를 사용할 수 있으며 제 글에서 일반적인 기술을 설명합니다.http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/ 를 참조해 주세요.

퍼포먼스에 관한 질문에는

  • DirectX 는, 프론트 버퍼로부터 읽어내는 속도가 매우 느린 경우를 제외하고, GDI 보다 고속으로 할 필요가 있습니다.내 접근 방식은 FRAPS(백버퍼에서 읽기)와 유사합니다.Direct3D 인터페이스에서 일련의 메서드를 인터셉트합니다.

  • 리얼타임(어플리케이션의 영향을 최소한으로 억제하고) 비디오 녹화를 실시하려면 , 고속 코덱이 불가결합니다.FRAPS는 자체 무손실 비디오코덱을 사용합니다.Lagarciate 및 HUFFYUV는 실시간애플리케이션용으로 설계된 범용 무손실 비디오코덱입니다비디오 파일을 출력하는 경우는, 그것들을 참조해 주세요.

  • 스크린캐스트를 녹화하는 또 다른 방법은 미러 드라이버를 쓰는 것입니다.위키피디아에 따르면:비디오 미러링이 액티브한 경우 시스템이 미러 영역 내의 위치에 있는 프라이머리 비디오 디바이스에 그릴 때마다 그리기 동작의 복사가 미러 비디오 디바이스 상에서 실시간으로 실행됩니다.MSDN 의 미러 드라이버를 참조해 주세요.http://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx

데스크톱 복제 API(Windows 8 이후 사용 가능)가 필요합니다.이는 공식적으로 권장되는 방법이며 CPU 효율도 가장 높습니다.

스크린캐스팅의 좋은 기능 중 하나는 윈도우의 움직임을 감지하여 윈도우가 이동할 때 원시 픽셀 대신 블록 델타 전송이 가능하다는 것입니다.또한 프레임 간에 변경된 직사각형도 알 수 있습니다.

Microsoft의 예제 코드는 매우 복잡하지만 API는 실제로 간단하고 사용하기 쉽습니다.저는 훨씬 더 간단한 프로젝트를 준비했습니다.

간단한 샘플 코드

Windows 데스크톱 중복 샘플

Microsoft 레퍼런스

데스크톱 복제 API

공식 예제 코드(위의 예제는 이 코드 제거 버전)

화면기록은 VLC API사용하여 C#에서 할 수 있습니다.저는 이것을 시연하기 위해 샘플 프로그램을 실행했습니다.LibVLCSarp 및 VideoLAN을 사용합니다.LibVLC.Windows 라이브러리이 크로스 플랫폼 API를 사용하면 비디오 렌더링과 관련된 더 많은 기능을 얻을 수 있습니다.

API 매뉴얼에 대해서는 LibVLCSarp API Github를 참조하십시오.

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using LibVLCSharp.Shared;

namespace ScreenRecorderNetApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Core.Initialize();

            using (var libVlc = new LibVLC())
            using (var mediaPlayer = new MediaPlayer(libVlc))
            {
                var media = new Media(libVlc, "screen://", FromType.FromLocation);
                media.AddOption(":screen-fps=24");
                media.AddOption(":sout=#transcode{vcodec=h264,vb=0,scale=0,acodec=mp4a,ab=128,channels=2,samplerate=44100}:file{dst=testvlc.mp4}");
                media.AddOption(":sout-keep");

                mediaPlayer.Play(media);
                Thread.Sleep(10*1000);
                mediaPlayer.Stop();
            }
        }
    }
}

이것이 가장 빠른 방법은 아닐 수도 있지만 가볍고 사용하기 쉽습니다.이미지는 RGB 색상을 포함하는 정수 배열로 반환됩니다.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include <Windows.h>
int* screenshot(int& width, int& height) {
    HDC hdc = GetDC(NULL); // get the desktop device context
    HDC cdc = CreateCompatibleDC(hdc); // create a device context to use yourself
    height = (int)GetSystemMetrics(SM_CYVIRTUALSCREEN); // get the width and height of the screen
    width  = 16*height/9; // only capture left monitor for dual screen setups, for both screens use (int)GetSystemMetrics(SM_CXVIRTUALSCREEN);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height); // create a bitmap
    SelectObject(cdc, hbitmap); // use the previously created device context with the bitmap
    BITMAPINFOHEADER bmi = { 0 };
    bmi.biSize = sizeof(BITMAPINFOHEADER);
    bmi.biPlanes = 1;
    bmi.biBitCount = 32;
    bmi.biWidth = width;
    bmi.biHeight = -height; // flip image upright
    bmi.biCompression = BI_RGB;
    bmi.biSizeImage = 3*width*height;
    BitBlt(cdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); // copy from desktop device context to bitmap device context
    ReleaseDC(NULL, hdc);
    int* image = new int[width*height];
    GetDIBits(cdc, hbitmap, 0, height, image, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
    DeleteObject(hbitmap);
    DeleteDC(cdc);
    return image;
}

위의 코드는 이 답변과 이 답변조합한 것입니다.

사용 방법의 예:

int main() {
    int width=0, height=0;
    int* image = screenshot(width, height);

    // access pixel colors for position (x|y)
    const int x=0, y=0;
    const int color = image[x+y*width];
    const int red   = (color>>16)&255;
    const int green = (color>> 8)&255;
    const int blue  =  color     &255;

    delete[] image;
}

My Impression에서는 GDI 어프로치와 DX 어프로치의 성질이 다릅니다.GDI를 사용한 페인팅은 FLUSH 방식을 적용하여 프레임을 그린 후 클리어하고 동일한 버퍼에 다른 프레임을 다시 그리기 때문에 게임에서는 높은 프레임률이 요구됩니다.

  1. DX가 빨라지는 이유DX(또는 그래픽스 월드)에서는 더블 버퍼 렌더링이라고 불리는 보다 성숙한 방법이 적용됩니다.여기서는 2개의 버퍼가 존재하며, 하드웨어에 프론트 버퍼를 제시하면 다른 버퍼에도 렌더링할 수 있습니다.그 후 프레임1이 렌더링을 종료하면 시스템은 다른 버퍼로 스왑됩니다(하드웨어에 제시하기 위해 시스템을 잠근 후).이 방법으로 렌더링의 비효율성이 크게 개선됩니다.
  2. 하드웨어 가속화를 더 빨리 줄이는 이유더블 버퍼 렌더링을 사용하면 FPS는 개선되지만 렌더링 시간은 한정되어 있습니다.현대 그래픽 하드웨어는 렌더링 중에 일반적으로 안티 에일리어싱과 같은 많은 최적화를 필요로 합니다.고품질의 그래픽을 필요로 하지 않으면 물론 이 옵션을 무효로 할 수도 있습니다.그러면 시간을 절약할 수 있을 거야

저는 당신에게 정말로 필요한 것은 리플레이 시스템이라고 생각합니다.저는 사람들이 논의한 것에 전적으로 동의합니다.

d3d9를 사용하여 백버퍼를 가져와 d3dx 라이브러리를 사용하여 png 파일에 저장합니다.

아이디렉트3DSurface9 * 표면;
// GetBackBufferidirect3device9 -> GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, & surface );
// 지표면 저장D3DXSaveSurfaceToFileA("filename.png", D3DX)IFF_PNG, 표면, NULL, NULL );
SAFE_RELEASE(표면);

이를 위해서는 와의 스왑 버퍼를 작성해야 합니다.

d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots.

(스크린샷을 찍기 전에 백버퍼가 망가지지 않도록 주의해 주세요).

저는 GDI 방식의 화면 캡처를 구현한 수업을 작성했습니다.저도 추가 속도를 원했기 때문에 (GetFrontBuffer를 통해) DirectX 방식을 발견하고 더 빠른 속도를 기대하며 시도했습니다.

GDI의 처리속도가 약 2.5배 빠르다는 것을 알고 깜짝 놀랐습니다.듀얼 모니터 디스플레이를 100번 캡처한 결과 GDI 구현은 화면 캡처당 평균 0.65초인 반면 DirectX 방식은 평균 1.72초였습니다.제 테스트에 따르면 GDI는 GetFrontBuffer보다 확실히 빠릅니다.

GetRenderTargetData에서 DirectX를 테스트하기 위한 Brandrew의 코드를 얻을 수 없었습니다.그 스크린 카피는 완전히 검은색으로 나왔다.하지만, 그것은 그 빈 화면을 매우 빠르게 복사할 수 있어요!나는 그것을 계속 만지작거릴 것이고 그것으로부터 진정한 결과를 볼 수 있는 작업 버전을 얻을 수 있기를 바란다.

DXGI 데스크톱 캡처

DXGI 복제로 데스크톱 이미지를 캡처하는 프로젝트입니다.캡처한 이미지를 다른 이미지 형식(*.bmp; *.jpg; *.tif)으로 파일에 저장합니다.

이 샘플은 C++로 기재되어 있습니다.DirectX(D3D11, D2D1)에 대한 경험도 필요합니다.

응용 프로그램의 기능

  • 데스크톱 모니터가 여러 개 있는 경우 선택할 수 있습니다.
  • 캡처한 데스크톱 이미지의 크기를 조정합니다.
  • 다른 스케일링 모드를 선택합니다.
  • 출력 영상에서 마우스 아이콘을 표시하거나 숨길 수 있습니다.
  • 출력 사진의 이미지를 회전하거나 기본값으로 둘 수 있습니다.

C++ 의 경우는, http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html 를 사용할 수 있습니다.
이것은 모든 종류의 3D 어플리케이션/비디오 앱에서 작동하지 않을 수 있습니다. 링크는 사용할 수 있는3가지 방법을 설명하고 있기 때문에 도움이 될 수 있습니다.

오래된 답변(C#):
시스템을 사용할 수 있습니다.드로잉.그래픽스알겠습니다만, 그리 빠르지는 않습니다.

제가 작성한 프로젝트 샘플은 http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/ 입니다.

이 샘플은 Direct3D와 같은 빠른 방법으로 업데이트할 예정입니다.http://spazzarama.com/2009/02/07/screencapture-with-direct3d/

다음은 비디오로 캡처하기 위한 링크입니다.C#.Net을 사용하여 화면을 비디오로 캡처하는 방법

강력한 화면 캡처 업체인 C++ 오픈 소스 프로젝트 WinRobot @git을 사용해 보십시오.

CComPtr<IWinRobotService> pService;
hr = pService.CoCreateInstance(__uuidof(ServiceHost) );

//get active console session
CComPtr<IUnknown> pUnk;
hr = pService->GetActiveConsoleSession(&pUnk);
CComQIPtr<IWinRobotSession> pSession = pUnk;

// capture screen
pUnk = 0;
hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk);

// get screen image data(with file mapping)
CComQIPtr<IScreenBufferStream> pBuffer = pUnk;

지원:

  • [UAC] 창
  • 윈로그온
  • DirectShowOverlay

OSS는 몰라도 미러 드라이버를 사용하는 것은 빠르다는 것을 알 수 있었습니다.

다른 리모트 컨트롤 소프트웨어에 비해 RDP가 고속인 이유는 무엇입니까?

또한 StretchRect의 일부 컨볼루션을 사용하는 것이 BitBlt보다 빠르다고 합니다.

http://betterlogic.com/roger/2010/07/fast-screen-capture/comment-page-1/ #180-5193

또한 D3D 어플리케이션에서는 (D3D dll에 접속하는 프랩)이 유일한 방법이지만 Windows XP 데스크톱 캡처에서는 동작하지 않습니다.이제 일반 데스크톱 윈도우에 대해 속도 면에서 동등한 프랩이 있었으면 합니다.누구 없어요?

(aero라면 프랩과 같은 후크를 사용할 수 있다고 생각합니다만, XP 사용자는 운이 없을 것입니다).

화면 비트 깊이를 변경하거나 하드웨어 액셀러레이션을 비활성화하면 도움이 될 수 있습니다(또는 aero 비활성화).

https://github.com/rdp/screen-capture-recorder-program에는 비교적 빠른 BitBlt 기반 캡처 유틸리티와 벤치마크 기능이 포함되어 있어 BitBlt 속도를 벤치마킹하여 최적화할 수 있습니다.

Virtual Dub에는 고속으로 변경 검출 등의 작업을 할 수 있는 "opengl" 화면 캡처 모듈도 있습니다.http://www.virtualdub.org/blog/pivot/entry.php?id=290

저 자신도 darest와 함께 하고 있고, 당신이 원하는 만큼 빠르다고 생각합니다. 빠른 코드 샘플은 없지만, 도움이 될 만한 것을 발견했습니다.debook11 버전은 크게 다르지 않을 것입니다. debook9은 조금 더 많을지도 모르지만, 그렇게 하는 것이 좋습니다.

다음의 제안은 당신의 질문에 대답할 수 없다는 것을 알지만, 빠르게 변화하는 DirectX 뷰를 캡처하는 가장 간단한 방법은 비디오카드의 S비디오 포트에 비디오 카메라를 꽂고 이미지를 동영상으로 기록하는 것입니다.그런 다음 카메라에서 MPG, WMV, AVI 등의 파일로 비디오를 다시 전송합니다.

언급URL : https://stackoverflow.com/questions/5069104/fastest-method-of-screen-capturing-on-windows

반응형