diff --git a/configure b/configure index eb77a52..4cf459f 100755 --- a/configure +++ b/configure @@ -881,6 +881,8 @@ avisynth_demuxer_deps="avisynth" bktr_demuxer_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" dirac_demuxer_deps="dirac_parser" dv1394_demuxer_deps="dv1394 dv_demuxer" +gdi_demuxer_deps="GetDeviceCaps" +gdi_demuxer_extralibs="-lgdi32" libdc1394_demuxer_deps="libdc1394" libnut_demuxer_deps="libnut" libnut_muxer_deps="libnut" @@ -1792,6 +1794,9 @@ EOF check_header linux/videodev.h check_header linux/videodev2.h +# Is this really needed? +check_func2 "windows.h wingdi.h" GetDeviceCaps -lgdi32 + check_func2 "windows.h vfw.h" capCreateCaptureWindow -lvfw32 # check for ioctl_meteor.h, ioctl_bt848.h and alternatives diff --git a/libavdevice/Makefile b/libavdevice/Makefile index 361eda4..3ab2d21 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -10,6 +10,7 @@ OBJS = alldevices.o # input/output devices OBJS-$(CONFIG_BKTR_DEMUXER) += bktr.o OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o +OBJS-$(CONFIG_GDI_DEMUXER) += gdi.o OBJS-$(CONFIG_OSS_DEMUXER) += audio.o OBJS-$(CONFIG_OSS_MUXER) += audio.o OBJS-$(CONFIG_V4L2_DEMUXER) += v4l2.o diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index 6dfd350..0b763aa 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -41,6 +41,7 @@ void avdevice_register_all(void) REGISTER_MUXDEMUX (AUDIO_BEOS, audio_beos); REGISTER_DEMUXER (BKTR, bktr); REGISTER_DEMUXER (DV1394, dv1394); + REGISTER_DEMUXER (GDI, gdi); REGISTER_MUXDEMUX (OSS, oss); REGISTER_DEMUXER (V4L2, v4l2); REGISTER_DEMUXER (V4L, v4l); diff --git a/libavdevice/gdi.c b/libavdevice/gdi.c new file mode 100644 index 0000000..5239256 --- /dev/null +++ b/libavdevice/gdi.c @@ -0,0 +1,144 @@ +/* + * GDI video grab interface + * Copyright (c) 2007 Ramiro Polla. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavformat/avformat.h" +#include +#include + +struct gdi_ctx { + HWND hDesktopWnd; + HDC hDesktopDC; + HDC hCaptureDC; + HBITMAP hCaptureBitmap; + BITMAPINFOHEADER *bih; + int x_off; + int y_off; +}; + +static int gdi_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + struct gdi_ctx *ctx = s->priv_data; + AVCodecContext *codec; + AVStream *st; + int width, height; + BITMAPINFOHEADER bih; + int bihsize = sizeof(BITMAPINFOHEADER); + + sscanf( s->filename, "%d,%d", &ctx->x_off, &ctx->y_off ); + memset( &bih, 0, sizeof(bih) ); + + width = GetSystemMetrics( SM_CXSCREEN ); + height = GetSystemMetrics( SM_CYSCREEN ); + + if( ctx->x_off + ap->width > width || ctx->y_off + ap->height > height ) + { + av_log( s, AV_LOG_ERROR, "Specified size greater than Desktop size." + " %d+%dx%d+%d > %dx%d\n", ctx->x_off, ap->width, + ctx->y_off, ap->height, width, height ); + return AVERROR_IO; + } + + width = ap->width ? ap->width : width - ctx->x_off; + height = ap->height ? ap->height : height - ctx->y_off; + + ctx->hDesktopWnd = GetDesktopWindow( ); + ctx->hDesktopDC = GetDC( ctx->hDesktopWnd ); + ctx->hCaptureDC = CreateCompatibleDC( ctx->hDesktopDC ); + ctx->hCaptureBitmap = CreateCompatibleBitmap( ctx->hDesktopDC, + width, height ); + SelectObject( ctx->hCaptureDC, ctx->hCaptureBitmap ); + + bih.biSize = bihsize; + GetDIBits( ctx->hCaptureDC, ctx->hCaptureBitmap, + 0, 0, NULL, &bih, DIB_RGB_COLORS ); + + if( bih.biCompression == 3 ) + bihsize += 0x10; + + ctx->bih = av_mallocz( bihsize ); + if( ctx->bih == NULL ) + return AVERROR_NOMEM; + + ctx->bih->biSize = bihsize; + GetDIBits( ctx->hCaptureDC, ctx->hCaptureBitmap, + 0, 0, NULL, ctx->bih, DIB_RGB_COLORS ); + + st = av_new_stream( s, 0 ); + if ( !st ) + return AVERROR_NOMEM; + + codec = st->codec; + codec->codec_type = CODEC_TYPE_VIDEO; + codec->codec_id = CODEC_ID_RAWVIDEO; + codec->bits_per_sample = ctx->bih->biBitCount; + if( ctx->bih->biCompression > 3 ) + codec->codec_tag = ctx->bih->biCompression; + codec->width = ctx->bih->biWidth; + codec->height = ctx->bih->biHeight; + codec->time_base = ap->time_base; + + av_set_pts_info( st, 32, 1, 1000 ); + + return 0; +} + +static int gdi_read_packet( AVFormatContext *s, AVPacket *pkt ) +{ + struct gdi_ctx *ctx = s->priv_data; + + if( av_new_packet( pkt, ctx->bih->biSizeImage ) < 0 ) + return AVERROR_IO; + + BitBlt( ctx->hCaptureDC, 0, 0, + ctx->bih->biWidth, ctx->bih->biHeight, + ctx->hDesktopDC, ctx->x_off, ctx->y_off, SRCCOPY | CAPTUREBLT ); + GetDIBits( ctx->hCaptureDC, ctx->hCaptureBitmap, + 0, ctx->bih->biHeight, pkt->data, ctx->bih, + DIB_RGB_COLORS ); + + pkt->pts = GetTickCount( ); + pkt->stream_index = 0; + + return pkt->size; +} + +static int gdi_read_close( AVFormatContext *s ) +{ + struct gdi_ctx *ctx = s->priv_data; + + av_free( ctx->bih ); + ReleaseDC( ctx->hDesktopWnd, ctx->hDesktopDC ); + DeleteDC( ctx->hCaptureDC ); + DeleteObject( ctx->hCaptureBitmap ); + + return 0; +} + +AVInputFormat gdi_demuxer = { + "gdi", + "GDI video grab", + sizeof(struct gdi_ctx), + NULL, + gdi_read_header, + gdi_read_packet, + gdi_read_close, + .flags = AVFMT_NOFILE, +};