X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavdevice%2Fvfwcap.c;h=3523fde6e17683df3b27aac29eca7805168d5342;hb=6dca24cd1d570b806b5a3fdaef9d3c8608942a81;hp=8c60f6d5e8a60d61561ca7d80976ee95d1b1cfb4;hpb=a9decf004189b86e110ccb70f728409db330a6c2;p=ffmpeg diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c index 8c60f6d5e8a..3523fde6e17 100644 --- a/libavdevice/vfwcap.c +++ b/libavdevice/vfwcap.c @@ -2,80 +2,92 @@ * VFW capture interface * Copyright (c) 2006-2008 Ramiro Polla * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav 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, + * Libav 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 + * License along with Libav; 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 - -//#define DEBUG_VFW +#include "libavutil/internal.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" -/* Defines for VFW missing from MinGW. - * Remove this when MinGW incorporates them. */ -#define HWND_MESSAGE ((HWND)-3) +#include "libavformat/avformat.h" +#include "libavformat/internal.h" -#define BI_RGB 0 +// windows.h must no be included before winsock2.h, and libavformat internal +// headers may include winsock2.h +#include +// windows.h needs to be included before vfw.h +#include -/* End of missing MinGW defines */ +/* Some obsolete versions of MinGW32 before 4.0.0 lack this. */ +#ifndef HWND_MESSAGE +#define HWND_MESSAGE ((HWND) -3) +#endif struct vfw_ctx { + const AVClass *class; HWND hwnd; HANDLE mutex; HANDLE event; AVPacketList *pktl; - AVFormatContext *s; unsigned int curbufsize; unsigned int frame_num; + char *video_size; /**< A string describing video size, set by a private option. */ + char *framerate; /**< Set by a private option. */ }; -static enum PixelFormat vfw_pixfmt(DWORD biCompression, WORD biBitCount) +static enum AVPixelFormat vfw_pixfmt(DWORD biCompression, WORD biBitCount) { switch(biCompression) { + case MKTAG('U', 'Y', 'V', 'Y'): + return AV_PIX_FMT_UYVY422; case MKTAG('Y', 'U', 'Y', '2'): - return PIX_FMT_YUYV422; + return AV_PIX_FMT_YUYV422; case MKTAG('I', '4', '2', '0'): - return PIX_FMT_YUV420P; + return AV_PIX_FMT_YUV420P; case BI_RGB: switch(biBitCount) { /* 1-8 are untested */ case 1: - return PIX_FMT_MONOWHITE; + return AV_PIX_FMT_MONOWHITE; case 4: - return PIX_FMT_RGB4; + return AV_PIX_FMT_RGB4; case 8: - return PIX_FMT_RGB8; + return AV_PIX_FMT_RGB8; case 16: - return PIX_FMT_RGB555; + return AV_PIX_FMT_RGB555; case 24: - return PIX_FMT_BGR24; + return AV_PIX_FMT_BGR24; case 32: - return PIX_FMT_RGB32; + return AV_PIX_FMT_RGB32; } } - return PIX_FMT_NONE; + return AV_PIX_FMT_NONE; } -static enum CodecID vfw_codecid(DWORD biCompression) +static enum AVCodecID vfw_codecid(DWORD biCompression) { switch(biCompression) { case MKTAG('d', 'v', 's', 'd'): - return CODEC_ID_DVVIDEO; + return AV_CODEC_ID_DVVIDEO; + case MKTAG('M', 'J', 'P', 'G'): + case MKTAG('m', 'j', 'p', 'g'): + return AV_CODEC_ID_MJPEG; } - return CODEC_ID_NONE; + return AV_CODEC_ID_NONE; } #define dstruct(pctx, sname, var, type) \ @@ -112,7 +124,7 @@ static void dump_captureparms(AVFormatContext *s, CAPTUREPARMS *cparms) static void dump_videohdr(AVFormatContext *s, VIDEOHDR *vhdr) { -#ifdef DEBUG_VFW +#ifdef DEBUG av_log(s, AV_LOG_DEBUG, "VIDEOHDR\n"); dstruct(s, vhdr, lpData, "p"); dstruct(s, vhdr, dwBufferLength, "lu"); @@ -145,15 +157,15 @@ static void dump_bih(AVFormatContext *s, BITMAPINFOHEADER *bih) dstruct(s, bih, biClrImportant, "lu"); } -static int shall_we_drop(struct vfw_ctx *ctx) +static int shall_we_drop(AVFormatContext *s) { - AVFormatContext *s = ctx->s; - const uint8_t dropscore[] = {62, 75, 87, 100}; + struct vfw_ctx *ctx = s->priv_data; + static const uint8_t dropscore[4] = { 62, 75, 87, 100 }; const int ndropscores = FF_ARRAY_ELEMS(dropscore); unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer; if(dropscore[++ctx->frame_num%ndropscores] <= buffer_fullness) { - av_log(ctx->s, AV_LOG_ERROR, + av_log(s, AV_LOG_ERROR, "real-time buffer %d%% full! frame dropped!\n", buffer_fullness); return 1; } @@ -163,14 +175,16 @@ static int shall_we_drop(struct vfw_ctx *ctx) static LRESULT CALLBACK videostream_cb(HWND hwnd, LPVIDEOHDR vdhdr) { + AVFormatContext *s; struct vfw_ctx *ctx; AVPacketList **ppktl, *pktl_next; - ctx = (struct vfw_ctx *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + s = (AVFormatContext *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + ctx = s->priv_data; - dump_videohdr(ctx->s, vdhdr); + dump_videohdr(s, vdhdr); - if(shall_we_drop(ctx)) + if(shall_we_drop(s)) return FALSE; WaitForSingleObject(ctx->mutex, INFINITE); @@ -204,6 +218,7 @@ fail: static int vfw_read_close(AVFormatContext *s) { struct vfw_ctx *ctx = s->priv_data; + AVPacketList *pktl; if(ctx->hwnd) { SendMessage(ctx->hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0); @@ -215,13 +230,21 @@ static int vfw_read_close(AVFormatContext *s) if(ctx->event) CloseHandle(ctx->event); + pktl = ctx->pktl; + while (pktl) { + AVPacketList *next = pktl->next; + av_packet_unref(&pktl->pkt); + av_free(pktl); + pktl = next; + } + return 0; } -static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) +static int vfw_read_header(AVFormatContext *s) { struct vfw_ctx *ctx = s->priv_data; - AVCodecContext *codec; + AVCodecParameters *par; AVStream *st; int devnum; int bisize; @@ -229,21 +252,29 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) CAPTUREPARMS cparms; DWORD biCompression; WORD biBitCount; - int width; - int height; int ret; - - if(!ap->time_base.den) { - av_log(s, AV_LOG_ERROR, "A time base must be specified.\n"); - return AVERROR_IO; + AVRational framerate_q; + + if (!strcmp(s->filename, "list")) { + for (devnum = 0; devnum <= 9; devnum++) { + char driver_name[256]; + char driver_ver[256]; + ret = capGetDriverDescription(devnum, + driver_name, sizeof(driver_name), + driver_ver, sizeof(driver_ver)); + if (ret) { + av_log(s, AV_LOG_INFO, "Driver %d\n", devnum); + av_log(s, AV_LOG_INFO, " %s\n", driver_name); + av_log(s, AV_LOG_INFO, " %s\n", driver_ver); + } + } + return AVERROR(EIO); } - ctx->s = s; - ctx->hwnd = capCreateCaptureWindow(NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0); if(!ctx->hwnd) { av_log(s, AV_LOG_ERROR, "Could not create capture window.\n"); - return AVERROR_IO; + return AVERROR(EIO); } /* If atoi fails, devnum==0 and the default device is used */ @@ -266,12 +297,12 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) goto fail_io; } - SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR) ctx); + SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR) s); - st = av_new_stream(s, 0); + st = avformat_new_stream(s, NULL); if(!st) { vfw_read_close(s); - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } /* Set video format */ @@ -281,7 +312,7 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) bi = av_malloc(bisize); if(!bi) { vfw_read_close(s); - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } ret = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, bisize, (LPARAM) bi); if(!ret) @@ -289,21 +320,25 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) dump_bih(s, &bi->bmiHeader); - width = ap->width ? ap->width : bi->bmiHeader.biWidth ; - height = ap->height ? ap->height : bi->bmiHeader.biHeight; - bi->bmiHeader.biWidth = width ; - bi->bmiHeader.biHeight = height; + + if (ctx->video_size) { + ret = av_parse_video_size(&bi->bmiHeader.biWidth, &bi->bmiHeader.biHeight, ctx->video_size); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Couldn't parse video size.\n"); + goto fail_bi; + } + } if (0) { - /* For testing yet unsupported compressions - * Copy these values from user-supplied verbose information */ - bi->bmiHeader.biWidth = 320; - bi->bmiHeader.biHeight = 240; - bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = 12; - bi->bmiHeader.biCompression = MKTAG('I','4','2','0'); - bi->bmiHeader.biSizeImage = 115200; - dump_bih(s, &bi->bmiHeader); + /* For testing yet unsupported compressions + * Copy these values from user-supplied verbose information */ + bi->bmiHeader.biWidth = 320; + bi->bmiHeader.biHeight = 240; + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 12; + bi->bmiHeader.biCompression = MKTAG('I','4','2','0'); + bi->bmiHeader.biSizeImage = 115200; + dump_bih(s, &bi->bmiHeader); } ret = SendMessage(ctx->hwnd, WM_CAP_SET_VIDEOFORMAT, bisize, (LPARAM) bi); @@ -327,7 +362,7 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) cparms.fYield = 1; // Spawn a background thread cparms.dwRequestMicroSecPerFrame = - (ap->time_base.num*1000000) / ap->time_base.den; + (framerate_q.den*1000000) / framerate_q.num; cparms.fAbortLeftMouse = 0; cparms.fAbortRightMouse = 0; cparms.fCaptureAudio = 0; @@ -338,28 +373,34 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) if(!ret) goto fail_io; - codec = st->codec; - codec->time_base = ap->time_base; - codec->codec_type = CODEC_TYPE_VIDEO; - codec->width = width; - codec->height = height; - codec->pix_fmt = vfw_pixfmt(biCompression, biBitCount); - if(codec->pix_fmt == PIX_FMT_NONE) { - codec->codec_id = vfw_codecid(biCompression); - if(codec->codec_id == CODEC_ID_NONE) { - av_log(s, AV_LOG_ERROR, "Unknown compression type. " - "Please report verbose (-v 9) debug information.\n"); + st->avg_frame_rate = framerate_q; + + par = st->codecpar; + par->codec_type = AVMEDIA_TYPE_VIDEO; + par->width = bi->bmiHeader.biWidth; + par->height = bi->bmiHeader.biHeight; + par->format = vfw_pixfmt(biCompression, biBitCount); + if (par->format == AV_PIX_FMT_NONE) { + par->codec_id = vfw_codecid(biCompression); + if (par->codec_id == AV_CODEC_ID_NONE) { + avpriv_report_missing_feature(s, "This compression type"); vfw_read_close(s); return AVERROR_PATCHWELCOME; } - codec->bits_per_coded_sample = biBitCount; + par->bits_per_coded_sample = biBitCount; } else { - codec->codec_id = CODEC_ID_RAWVIDEO; - if(biCompression == BI_RGB) - codec->bits_per_coded_sample = biBitCount; + par->codec_id = AV_CODEC_ID_RAWVIDEO; + if(biCompression == BI_RGB) { + par->bits_per_coded_sample = biBitCount; + par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE); + if (par->extradata) { + par->extradata_size = 9; + memcpy(par->extradata, "BottomUp", 9); + } + } } - av_set_pts_info(st, 32, 1, 1000); + avpriv_set_pts_info(st, 32, 1, 1000); ctx->mutex = CreateMutex(NULL, 0, NULL); if(!ctx->mutex) { @@ -385,7 +426,7 @@ fail_bi: fail_io: vfw_read_close(s); - return AVERROR_IO; + return AVERROR(EIO); } static int vfw_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -417,13 +458,28 @@ static int vfw_read_packet(AVFormatContext *s, AVPacket *pkt) return pkt->size; } -AVInputFormat vfwcap_demuxer = { - "vfwcap", - NULL_IF_CONFIG_SMALL("VFW video capture"), - sizeof(struct vfw_ctx), - NULL, - vfw_read_header, - vfw_read_packet, - vfw_read_close, - .flags = AVFMT_NOFILE, +#define OFFSET(x) offsetof(struct vfw_ctx, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC }, + { NULL }, +}; + +static const AVClass vfw_class = { + .class_name = "VFW indev", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_vfwcap_demuxer = { + .name = "vfwcap", + .long_name = NULL_IF_CONFIG_SMALL("VfW video capture"), + .priv_data_size = sizeof(struct vfw_ctx), + .read_header = vfw_read_header, + .read_packet = vfw_read_packet, + .read_close = vfw_read_close, + .flags = AVFMT_NOFILE, + .priv_class = &vfw_class, };