70 #define WIN32_API_ERROR(str) \ 71 av_log(s1, AV_LOG_ERROR, str " (error %li)\n", GetLastError()) 73 #define REGION_WND_BORDER 3 86 static LRESULT CALLBACK
95 hdc = BeginPaint(hwnd, &ps);
97 GetClientRect(hwnd, &rect);
98 FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
100 rect.left++; rect.top++; rect.right--; rect.bottom--;
101 FrameRect(hdc, &rect, GetStockObject(WHITE_BRUSH));
103 rect.left++; rect.top++; rect.right--; rect.bottom--;
104 FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
109 return DefWindowProc(hwnd, msg, wparam, lparam);
127 HRGN region_interior =
NULL;
129 DWORD style = WS_POPUP | WS_VISIBLE;
130 DWORD ex = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT;
135 AdjustWindowRectEx(&rect, style, FALSE, ex);
139 hwnd = CreateWindowEx(ex, WC_DIALOG,
NULL, style, rect.left, rect.top,
140 rect.right - rect.left, rect.bottom - rect.top,
148 GetClientRect(hwnd, &rect);
149 region = CreateRectRgn(0, 0,
150 rect.right - rect.left, rect.bottom - rect.top);
154 CombineRgn(region, region, region_interior, RGN_DIFF);
155 if (!SetWindowRgn(hwnd, region, FALSE)) {
161 DeleteObject(region_interior);
165 ShowWindow(hwnd, SW_SHOW);
173 DeleteObject(region);
175 DeleteObject(region_interior);
211 while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
212 DispatchMessage(&msg);
234 const char *filename = s1->
url;
248 if (!strncmp(filename,
"title=", 6)) {
249 wchar_t *name_w =
NULL;
252 if(utf8towchar(name, &name_w)) {
261 hwnd = FindWindowW(
NULL, name_w);
265 "Can't find window '%s', aborting.\n", name);
271 "Can't show region when grabbing a window.\n");
274 }
else if (!strcmp(filename,
"desktop")) {
278 "Please use \"desktop\" or \"title=<windowname>\" to specify your target.\n");
285 source_hdc = GetDC(hwnd);
291 bpp = GetDeviceCaps(source_hdc, BITSPIXEL);
293 horzres = GetDeviceCaps(source_hdc, HORZRES);
294 vertres = GetDeviceCaps(source_hdc, VERTRES);
295 desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES);
296 desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES);
299 GetClientRect(hwnd, &virtual_rect);
301 virtual_rect.left = virtual_rect.left * desktophorzres / horzres;
302 virtual_rect.right = virtual_rect.right * desktophorzres / horzres;
303 virtual_rect.top = virtual_rect.top * desktopvertres / vertres;
304 virtual_rect.bottom = virtual_rect.bottom * desktopvertres / vertres;
307 virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
308 virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
309 virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktophorzres / horzres;
310 virtual_rect.bottom = (virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN)) * desktopvertres / vertres;
315 clip_rect.left = virtual_rect.left;
316 clip_rect.top = virtual_rect.top;
317 clip_rect.right = virtual_rect.right;
318 clip_rect.bottom = virtual_rect.bottom;
326 if (clip_rect.left < virtual_rect.left ||
327 clip_rect.top < virtual_rect.top ||
328 clip_rect.right > virtual_rect.right ||
329 clip_rect.bottom > virtual_rect.bottom) {
331 "Capture area (%li,%li),(%li,%li) extends outside window area (%li,%li),(%li,%li)",
332 clip_rect.left, clip_rect.top,
333 clip_rect.right, clip_rect.bottom,
334 virtual_rect.left, virtual_rect.top,
335 virtual_rect.right, virtual_rect.bottom);
343 "Found window %s, capturing %lix%lix%i at (%li,%li)\n",
345 clip_rect.right - clip_rect.left,
346 clip_rect.bottom - clip_rect.top,
347 bpp, clip_rect.left, clip_rect.top);
350 "Capturing whole desktop as %lix%lix%i at (%li,%li)\n",
351 clip_rect.right - clip_rect.left,
352 clip_rect.bottom - clip_rect.top,
353 bpp, clip_rect.left, clip_rect.top);
356 if (clip_rect.right - clip_rect.left <= 0 ||
357 clip_rect.bottom - clip_rect.top <= 0 || bpp%8) {
363 dest_hdc = CreateCompatibleDC(source_hdc);
371 bmi.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
372 bmi.bmiHeader.biWidth = clip_rect.right - clip_rect.left;
373 bmi.bmiHeader.biHeight = -(clip_rect.bottom - clip_rect.top);
374 bmi.bmiHeader.biPlanes = 1;
375 bmi.bmiHeader.biBitCount = bpp;
376 bmi.bmiHeader.biCompression = BI_RGB;
377 bmi.bmiHeader.biSizeImage = 0;
378 bmi.bmiHeader.biXPelsPerMeter = 0;
379 bmi.bmiHeader.biYPelsPerMeter = 0;
380 bmi.bmiHeader.biClrUsed = 0;
381 bmi.bmiHeader.biClrImportant = 0;
382 hbmp = CreateDIBSection(dest_hdc, &bmi, DIB_RGB_COLORS,
390 if (!SelectObject(dest_hdc, hbmp)) {
397 GetObject(hbmp,
sizeof(BITMAP), &bmp);
406 gdigrab->
frame_size = bmp.bmWidthBytes * bmp.bmHeight * bmp.bmPlanes;
407 gdigrab->
header_size =
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
408 (bpp <= 8 ? (1 << bpp) : 0) *
sizeof(RGBQUAD) ;
439 ReleaseDC(hwnd, source_hdc);
445 DeleteDC(source_hdc);
459 #define CURSOR_ERROR(str) \ 460 if (!gdigrab->cursor_error_printed) { \ 461 WIN32_API_ERROR(str); \ 462 gdigrab->cursor_error_printed = 1; \ 465 ci.cbSize =
sizeof(ci);
467 if (GetCursorInfo(&ci)) {
468 HCURSOR icon = CopyCursor(ci.hCursor);
473 int horzres = GetDeviceCaps(gdigrab->
source_hdc, HORZRES);
474 int vertres = GetDeviceCaps(gdigrab->
source_hdc, VERTRES);
475 int desktophorzres = GetDeviceCaps(gdigrab->
source_hdc, DESKTOPHORZRES);
476 int desktopvertres = GetDeviceCaps(gdigrab->
source_hdc, DESKTOPVERTRES);
478 info.hbmColor =
NULL;
480 if (ci.flags != CURSOR_SHOWING)
487 icon = CopyCursor(LoadCursor(
NULL, IDC_ARROW));
490 if (!GetIconInfo(icon, &info)) {
498 if (GetWindowRect(hwnd, &rect)) {
499 pos.
x = ci.ptScreenPos.x - clip_rect.left - info.xHotspot - rect.left;
500 pos.y = ci.ptScreenPos.y - clip_rect.top - info.yHotspot - rect.top;
503 pos.x = pos.x * desktophorzres / horzres;
504 pos.y = pos.y * desktopvertres / vertres;
511 pos.x = ci.ptScreenPos.x * desktophorzres / horzres - clip_rect.left - info.xHotspot;
512 pos.y = ci.ptScreenPos.y * desktopvertres / vertres - clip_rect.top - info.yHotspot;
516 ci.ptScreenPos.x, ci.ptScreenPos.y, pos.x, pos.y);
518 if (pos.x >= 0 && pos.x <= clip_rect.right - clip_rect.left &&
519 pos.y >= 0 && pos.y <= clip_rect.bottom - clip_rect.top) {
520 if (!DrawIcon(gdigrab->
dest_hdc, pos.x, pos.y, icon))
526 DeleteObject(info.hbmMask);
528 DeleteObject(info.hbmColor);
553 BITMAPFILEHEADER bfh;
556 int64_t curtime, delay;
559 time_frame += INT64_C(1000000);
568 delay = time_frame *
av_q2d(time_base) - curtime;
570 if (delay < INT64_C(-1000000) *
av_q2d(time_base)) {
571 time_frame += INT64_C(1000000);
587 if (!BitBlt(dest_hdc, 0, 0,
588 clip_rect.right - clip_rect.left,
589 clip_rect.bottom - clip_rect.top,
591 clip_rect.left, clip_rect.top, SRCCOPY | CAPTUREBLT)) {
601 bfh.bfSize = file_size;
606 memcpy(pkt->
data, &bfh,
sizeof(bfh));
608 memcpy(pkt->
data +
sizeof(bfh), &gdigrab->
bmi.bmiHeader,
sizeof(gdigrab->
bmi.bmiHeader));
610 if (gdigrab->
bmi.bmiHeader.biBitCount <= 8)
611 GetDIBColorTable(dest_hdc, 0, 1 << gdigrab->
bmi.bmiHeader.biBitCount,
612 (RGBQUAD *) (pkt->
data +
sizeof(bfh) +
sizeof(gdigrab->
bmi.bmiHeader)));
639 DeleteObject(s->
hbmp);
646 #define OFFSET(x) offsetof(struct gdigrab, x) 647 #define DEC AV_OPT_FLAG_DECODING_PARAM 670 .priv_data_size =
sizeof(
struct gdigrab),
static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
Grabs a frame from gdi (public device demuxer API).
int show_region
Draw border (private option)
#define AV_LOG_WARNING
Something somehow does not look correct.
#define LIBAVUTIL_VERSION_INT
static const AVOption options[]
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
const char * av_default_item_name(void *ptr)
Return the context name.
int frame_size
Size in bytes of the frame pixel data.
BITMAPINFO bmi
Information describing DIB format.
int av_usleep(unsigned usec)
Sleep for a period of time.
HWND region_hwnd
Handle of the region border window.
static void error(const char *err)
static int gdigrab_read_close(AVFormatContext *s1)
Closes gdi frame grabber (public device demuxer API).
static void gdigrab_region_wnd_destroy(AVFormatContext *s1, struct gdigrab *gdigrab)
Cleanup/free the region outline window.
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
RECT clip_rect
The subarea of the screen or window to clip.
static LRESULT CALLBACK gdigrab_region_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
Callback to handle Windows messages for the region outline window.
int flags
Flags modifying the (de)muxer behaviour.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
AVInputFormat ff_gdigrab_demuxer
gdi grabber device demuxer declaration
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
static int gdigrab_read_header(AVFormatContext *s1)
Initializes the gdi grab device demuxer (public device demuxer API).
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
char * url
input or output URL.
HBITMAP hbmp
Information on the bitmap captured.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
enum AVMediaType codec_type
General type of the encoded data.
AVRational framerate
Capture framerate (private option)
AVRational avg_frame_rate
Average framerate.
int64_t time_frame
Current time.
static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab)
Paints a mouse pointer in a Win32 image.
static const AVClass gdigrab_class
int height
Height of the grab frame (private option)
AVRational time_base
Time base.
int header_size
Size in bytes of the DIB header.
HDC dest_hdc
Destination, source-compatible DC.
#define REGION_WND_BORDER
GDI Device Demuxer context.
void * buffer
The buffer containing the bitmap image data.
#define WIN32_API_ERROR(str)
int64_t av_gettime(void)
Get the current time in microseconds.
HWND hwnd
Handle of the window for the grab.
#define AV_LOG_INFO
Standard information.
int offset_y
Capture y offset (private option)
Describe the class of an AVClass context structure.
Rational number (pair of numerator and denominator).
HDC source_hdc
Source device context.
offset must point to AVRational
offset must point to two consecutive integers
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
int width
Width of the grab frame (private option)
int draw_mouse
Draw mouse cursor (private option)
static int gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
Initialize the region outline window.
void * priv_data
Format private data.
int offset_x
Capture x offset (private option)
#define CURSOR_ERROR(str)
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
This structure stores compressed data.
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
static void gdigrab_region_wnd_update(AVFormatContext *s1, struct gdigrab *gdigrab)
Process the Windows message queue.