Libav 0.7.1
|
00001 /* 00002 * VFW capture interface 00003 * Copyright (c) 2006-2008 Ramiro Polla 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavformat/avformat.h" 00023 #include "libavutil/log.h" 00024 #include "libavutil/opt.h" 00025 #include "libavutil/parseutils.h" 00026 #include <windows.h> 00027 #include <vfw.h> 00028 00029 /* Defines for VFW missing from MinGW. 00030 * Remove this when MinGW incorporates them. */ 00031 #define HWND_MESSAGE ((HWND)-3) 00032 00033 #define BI_RGB 0 00034 00035 /* End of missing MinGW defines */ 00036 00037 struct vfw_ctx { 00038 const AVClass *class; 00039 HWND hwnd; 00040 HANDLE mutex; 00041 HANDLE event; 00042 AVPacketList *pktl; 00043 unsigned int curbufsize; 00044 unsigned int frame_num; 00045 char *video_size; 00046 char *framerate; 00047 }; 00048 00049 static enum PixelFormat vfw_pixfmt(DWORD biCompression, WORD biBitCount) 00050 { 00051 switch(biCompression) { 00052 case MKTAG('U', 'Y', 'V', 'Y'): 00053 return PIX_FMT_UYVY422; 00054 case MKTAG('Y', 'U', 'Y', '2'): 00055 return PIX_FMT_YUYV422; 00056 case MKTAG('I', '4', '2', '0'): 00057 return PIX_FMT_YUV420P; 00058 case BI_RGB: 00059 switch(biBitCount) { /* 1-8 are untested */ 00060 case 1: 00061 return PIX_FMT_MONOWHITE; 00062 case 4: 00063 return PIX_FMT_RGB4; 00064 case 8: 00065 return PIX_FMT_RGB8; 00066 case 16: 00067 return PIX_FMT_RGB555; 00068 case 24: 00069 return PIX_FMT_BGR24; 00070 case 32: 00071 return PIX_FMT_RGB32; 00072 } 00073 } 00074 return PIX_FMT_NONE; 00075 } 00076 00077 static enum CodecID vfw_codecid(DWORD biCompression) 00078 { 00079 switch(biCompression) { 00080 case MKTAG('d', 'v', 's', 'd'): 00081 return CODEC_ID_DVVIDEO; 00082 case MKTAG('M', 'J', 'P', 'G'): 00083 case MKTAG('m', 'j', 'p', 'g'): 00084 return CODEC_ID_MJPEG; 00085 } 00086 return CODEC_ID_NONE; 00087 } 00088 00089 #define dstruct(pctx, sname, var, type) \ 00090 av_log(pctx, AV_LOG_DEBUG, #var":\t%"type"\n", sname->var) 00091 00092 static void dump_captureparms(AVFormatContext *s, CAPTUREPARMS *cparms) 00093 { 00094 av_log(s, AV_LOG_DEBUG, "CAPTUREPARMS\n"); 00095 dstruct(s, cparms, dwRequestMicroSecPerFrame, "lu"); 00096 dstruct(s, cparms, fMakeUserHitOKToCapture, "d"); 00097 dstruct(s, cparms, wPercentDropForError, "u"); 00098 dstruct(s, cparms, fYield, "d"); 00099 dstruct(s, cparms, dwIndexSize, "lu"); 00100 dstruct(s, cparms, wChunkGranularity, "u"); 00101 dstruct(s, cparms, fUsingDOSMemory, "d"); 00102 dstruct(s, cparms, wNumVideoRequested, "u"); 00103 dstruct(s, cparms, fCaptureAudio, "d"); 00104 dstruct(s, cparms, wNumAudioRequested, "u"); 00105 dstruct(s, cparms, vKeyAbort, "u"); 00106 dstruct(s, cparms, fAbortLeftMouse, "d"); 00107 dstruct(s, cparms, fAbortRightMouse, "d"); 00108 dstruct(s, cparms, fLimitEnabled, "d"); 00109 dstruct(s, cparms, wTimeLimit, "u"); 00110 dstruct(s, cparms, fMCIControl, "d"); 00111 dstruct(s, cparms, fStepMCIDevice, "d"); 00112 dstruct(s, cparms, dwMCIStartTime, "lu"); 00113 dstruct(s, cparms, dwMCIStopTime, "lu"); 00114 dstruct(s, cparms, fStepCaptureAt2x, "d"); 00115 dstruct(s, cparms, wStepCaptureAverageFrames, "u"); 00116 dstruct(s, cparms, dwAudioBufferSize, "lu"); 00117 dstruct(s, cparms, fDisableWriteCache, "d"); 00118 dstruct(s, cparms, AVStreamMaster, "u"); 00119 } 00120 00121 static void dump_videohdr(AVFormatContext *s, VIDEOHDR *vhdr) 00122 { 00123 #ifdef DEBUG 00124 av_log(s, AV_LOG_DEBUG, "VIDEOHDR\n"); 00125 dstruct(s, vhdr, lpData, "p"); 00126 dstruct(s, vhdr, dwBufferLength, "lu"); 00127 dstruct(s, vhdr, dwBytesUsed, "lu"); 00128 dstruct(s, vhdr, dwTimeCaptured, "lu"); 00129 dstruct(s, vhdr, dwUser, "lu"); 00130 dstruct(s, vhdr, dwFlags, "lu"); 00131 dstruct(s, vhdr, dwReserved[0], "lu"); 00132 dstruct(s, vhdr, dwReserved[1], "lu"); 00133 dstruct(s, vhdr, dwReserved[2], "lu"); 00134 dstruct(s, vhdr, dwReserved[3], "lu"); 00135 #endif 00136 } 00137 00138 static void dump_bih(AVFormatContext *s, BITMAPINFOHEADER *bih) 00139 { 00140 av_log(s, AV_LOG_DEBUG, "BITMAPINFOHEADER\n"); 00141 dstruct(s, bih, biSize, "lu"); 00142 dstruct(s, bih, biWidth, "ld"); 00143 dstruct(s, bih, biHeight, "ld"); 00144 dstruct(s, bih, biPlanes, "d"); 00145 dstruct(s, bih, biBitCount, "d"); 00146 dstruct(s, bih, biCompression, "lu"); 00147 av_log(s, AV_LOG_DEBUG, " biCompression:\t\"%.4s\"\n", 00148 (char*) &bih->biCompression); 00149 dstruct(s, bih, biSizeImage, "lu"); 00150 dstruct(s, bih, biXPelsPerMeter, "lu"); 00151 dstruct(s, bih, biYPelsPerMeter, "lu"); 00152 dstruct(s, bih, biClrUsed, "lu"); 00153 dstruct(s, bih, biClrImportant, "lu"); 00154 } 00155 00156 static int shall_we_drop(AVFormatContext *s) 00157 { 00158 struct vfw_ctx *ctx = s->priv_data; 00159 const uint8_t dropscore[] = {62, 75, 87, 100}; 00160 const int ndropscores = FF_ARRAY_ELEMS(dropscore); 00161 unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer; 00162 00163 if(dropscore[++ctx->frame_num%ndropscores] <= buffer_fullness) { 00164 av_log(s, AV_LOG_ERROR, 00165 "real-time buffer %d%% full! frame dropped!\n", buffer_fullness); 00166 return 1; 00167 } 00168 00169 return 0; 00170 } 00171 00172 static LRESULT CALLBACK videostream_cb(HWND hwnd, LPVIDEOHDR vdhdr) 00173 { 00174 AVFormatContext *s; 00175 struct vfw_ctx *ctx; 00176 AVPacketList **ppktl, *pktl_next; 00177 00178 s = (AVFormatContext *) GetWindowLongPtr(hwnd, GWLP_USERDATA); 00179 ctx = s->priv_data; 00180 00181 dump_videohdr(s, vdhdr); 00182 00183 if(shall_we_drop(s)) 00184 return FALSE; 00185 00186 WaitForSingleObject(ctx->mutex, INFINITE); 00187 00188 pktl_next = av_mallocz(sizeof(AVPacketList)); 00189 if(!pktl_next) 00190 goto fail; 00191 00192 if(av_new_packet(&pktl_next->pkt, vdhdr->dwBytesUsed) < 0) { 00193 av_free(pktl_next); 00194 goto fail; 00195 } 00196 00197 pktl_next->pkt.pts = vdhdr->dwTimeCaptured; 00198 memcpy(pktl_next->pkt.data, vdhdr->lpData, vdhdr->dwBytesUsed); 00199 00200 for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next); 00201 *ppktl = pktl_next; 00202 00203 ctx->curbufsize += vdhdr->dwBytesUsed; 00204 00205 SetEvent(ctx->event); 00206 ReleaseMutex(ctx->mutex); 00207 00208 return TRUE; 00209 fail: 00210 ReleaseMutex(ctx->mutex); 00211 return FALSE; 00212 } 00213 00214 static int vfw_read_close(AVFormatContext *s) 00215 { 00216 struct vfw_ctx *ctx = s->priv_data; 00217 AVPacketList *pktl; 00218 00219 if(ctx->hwnd) { 00220 SendMessage(ctx->hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0); 00221 SendMessage(ctx->hwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0); 00222 DestroyWindow(ctx->hwnd); 00223 } 00224 if(ctx->mutex) 00225 CloseHandle(ctx->mutex); 00226 if(ctx->event) 00227 CloseHandle(ctx->event); 00228 00229 pktl = ctx->pktl; 00230 while (pktl) { 00231 AVPacketList *next = pktl->next; 00232 av_destruct_packet(&pktl->pkt); 00233 av_free(pktl); 00234 pktl = next; 00235 } 00236 00237 return 0; 00238 } 00239 00240 static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap) 00241 { 00242 struct vfw_ctx *ctx = s->priv_data; 00243 AVCodecContext *codec; 00244 AVStream *st; 00245 int devnum; 00246 int bisize; 00247 BITMAPINFO *bi; 00248 CAPTUREPARMS cparms; 00249 DWORD biCompression; 00250 WORD biBitCount; 00251 int ret; 00252 AVRational fps; 00253 00254 if (!strcmp(s->filename, "list")) { 00255 for (devnum = 0; devnum <= 9; devnum++) { 00256 char driver_name[256]; 00257 char driver_ver[256]; 00258 ret = capGetDriverDescription(devnum, 00259 driver_name, sizeof(driver_name), 00260 driver_ver, sizeof(driver_ver)); 00261 if (ret) { 00262 av_log(s, AV_LOG_INFO, "Driver %d\n", devnum); 00263 av_log(s, AV_LOG_INFO, " %s\n", driver_name); 00264 av_log(s, AV_LOG_INFO, " %s\n", driver_ver); 00265 } 00266 } 00267 return AVERROR(EIO); 00268 } 00269 00270 #if FF_API_FORMAT_PARAMETERS 00271 if (ap->time_base.num) 00272 fps = (AVRational){ap->time_base.den, ap->time_base.num}; 00273 #endif 00274 00275 ctx->hwnd = capCreateCaptureWindow(NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0); 00276 if(!ctx->hwnd) { 00277 av_log(s, AV_LOG_ERROR, "Could not create capture window.\n"); 00278 return AVERROR(EIO); 00279 } 00280 00281 /* If atoi fails, devnum==0 and the default device is used */ 00282 devnum = atoi(s->filename); 00283 00284 ret = SendMessage(ctx->hwnd, WM_CAP_DRIVER_CONNECT, devnum, 0); 00285 if(!ret) { 00286 av_log(s, AV_LOG_ERROR, "Could not connect to device.\n"); 00287 DestroyWindow(ctx->hwnd); 00288 return AVERROR(ENODEV); 00289 } 00290 00291 SendMessage(ctx->hwnd, WM_CAP_SET_OVERLAY, 0, 0); 00292 SendMessage(ctx->hwnd, WM_CAP_SET_PREVIEW, 0, 0); 00293 00294 ret = SendMessage(ctx->hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 00295 (LPARAM) videostream_cb); 00296 if(!ret) { 00297 av_log(s, AV_LOG_ERROR, "Could not set video stream callback.\n"); 00298 goto fail_io; 00299 } 00300 00301 SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR) s); 00302 00303 st = av_new_stream(s, 0); 00304 if(!st) { 00305 vfw_read_close(s); 00306 return AVERROR(ENOMEM); 00307 } 00308 00309 /* Set video format */ 00310 bisize = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0); 00311 if(!bisize) 00312 goto fail_io; 00313 bi = av_malloc(bisize); 00314 if(!bi) { 00315 vfw_read_close(s); 00316 return AVERROR(ENOMEM); 00317 } 00318 ret = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, bisize, (LPARAM) bi); 00319 if(!ret) 00320 goto fail_bi; 00321 00322 dump_bih(s, &bi->bmiHeader); 00323 00324 00325 if (ctx->video_size) { 00326 ret = av_parse_video_size(&bi->bmiHeader.biWidth, &bi->bmiHeader.biHeight, ctx->video_size); 00327 if (ret < 0) { 00328 av_log(s, AV_LOG_ERROR, "Couldn't parse video size.\n"); 00329 goto fail_bi; 00330 } 00331 } 00332 #if FF_API_FORMAT_PARAMETERS 00333 if (ap->width > 0) 00334 bi->bmiHeader.biWidth = ap->width; 00335 if (ap->height > 0) 00336 bi->bmiHeader.biHeight = ap->height; 00337 #endif 00338 00339 if (0) { 00340 /* For testing yet unsupported compressions 00341 * Copy these values from user-supplied verbose information */ 00342 bi->bmiHeader.biWidth = 320; 00343 bi->bmiHeader.biHeight = 240; 00344 bi->bmiHeader.biPlanes = 1; 00345 bi->bmiHeader.biBitCount = 12; 00346 bi->bmiHeader.biCompression = MKTAG('I','4','2','0'); 00347 bi->bmiHeader.biSizeImage = 115200; 00348 dump_bih(s, &bi->bmiHeader); 00349 } 00350 00351 ret = SendMessage(ctx->hwnd, WM_CAP_SET_VIDEOFORMAT, bisize, (LPARAM) bi); 00352 if(!ret) { 00353 av_log(s, AV_LOG_ERROR, "Could not set Video Format.\n"); 00354 goto fail_bi; 00355 } 00356 00357 biCompression = bi->bmiHeader.biCompression; 00358 biBitCount = bi->bmiHeader.biBitCount; 00359 00360 av_free(bi); 00361 00362 /* Set sequence setup */ 00363 ret = SendMessage(ctx->hwnd, WM_CAP_GET_SEQUENCE_SETUP, sizeof(cparms), 00364 (LPARAM) &cparms); 00365 if(!ret) 00366 goto fail_io; 00367 00368 dump_captureparms(s, &cparms); 00369 00370 cparms.fYield = 1; // Spawn a background thread 00371 cparms.dwRequestMicroSecPerFrame = 00372 (fps.den*1000000) / fps.num; 00373 cparms.fAbortLeftMouse = 0; 00374 cparms.fAbortRightMouse = 0; 00375 cparms.fCaptureAudio = 0; 00376 cparms.vKeyAbort = 0; 00377 00378 ret = SendMessage(ctx->hwnd, WM_CAP_SET_SEQUENCE_SETUP, sizeof(cparms), 00379 (LPARAM) &cparms); 00380 if(!ret) 00381 goto fail_io; 00382 00383 codec = st->codec; 00384 codec->time_base = (AVRational){fps.den, fps.num}; 00385 codec->codec_type = AVMEDIA_TYPE_VIDEO; 00386 codec->width = bi->bmiHeader.biWidth; 00387 codec->height = bi->bmiHeader.biHeight; 00388 codec->pix_fmt = vfw_pixfmt(biCompression, biBitCount); 00389 if(codec->pix_fmt == PIX_FMT_NONE) { 00390 codec->codec_id = vfw_codecid(biCompression); 00391 if(codec->codec_id == CODEC_ID_NONE) { 00392 av_log(s, AV_LOG_ERROR, "Unknown compression type. " 00393 "Please report verbose (-v 9) debug information.\n"); 00394 vfw_read_close(s); 00395 return AVERROR_PATCHWELCOME; 00396 } 00397 codec->bits_per_coded_sample = biBitCount; 00398 } else { 00399 codec->codec_id = CODEC_ID_RAWVIDEO; 00400 if(biCompression == BI_RGB) { 00401 codec->bits_per_coded_sample = biBitCount; 00402 codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE); 00403 if (codec->extradata) { 00404 codec->extradata_size = 9; 00405 memcpy(codec->extradata, "BottomUp", 9); 00406 } 00407 } 00408 } 00409 00410 av_set_pts_info(st, 32, 1, 1000); 00411 00412 ctx->mutex = CreateMutex(NULL, 0, NULL); 00413 if(!ctx->mutex) { 00414 av_log(s, AV_LOG_ERROR, "Could not create Mutex.\n" ); 00415 goto fail_io; 00416 } 00417 ctx->event = CreateEvent(NULL, 1, 0, NULL); 00418 if(!ctx->event) { 00419 av_log(s, AV_LOG_ERROR, "Could not create Event.\n" ); 00420 goto fail_io; 00421 } 00422 00423 ret = SendMessage(ctx->hwnd, WM_CAP_SEQUENCE_NOFILE, 0, 0); 00424 if(!ret) { 00425 av_log(s, AV_LOG_ERROR, "Could not start capture sequence.\n" ); 00426 goto fail_io; 00427 } 00428 00429 return 0; 00430 00431 fail_bi: 00432 av_free(bi); 00433 00434 fail_io: 00435 vfw_read_close(s); 00436 return AVERROR(EIO); 00437 } 00438 00439 static int vfw_read_packet(AVFormatContext *s, AVPacket *pkt) 00440 { 00441 struct vfw_ctx *ctx = s->priv_data; 00442 AVPacketList *pktl = NULL; 00443 00444 while(!pktl) { 00445 WaitForSingleObject(ctx->mutex, INFINITE); 00446 pktl = ctx->pktl; 00447 if(ctx->pktl) { 00448 *pkt = ctx->pktl->pkt; 00449 ctx->pktl = ctx->pktl->next; 00450 av_free(pktl); 00451 } 00452 ResetEvent(ctx->event); 00453 ReleaseMutex(ctx->mutex); 00454 if(!pktl) { 00455 if(s->flags & AVFMT_FLAG_NONBLOCK) { 00456 return AVERROR(EAGAIN); 00457 } else { 00458 WaitForSingleObject(ctx->event, INFINITE); 00459 } 00460 } 00461 } 00462 00463 ctx->curbufsize -= pkt->size; 00464 00465 return pkt->size; 00466 } 00467 00468 #define OFFSET(x) offsetof(struct vfw_ctx, x) 00469 #define DEC AV_OPT_FLAG_DECODING_PARAM 00470 static const AVOption options[] = { 00471 { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, 00472 { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC }, 00473 { NULL }, 00474 }; 00475 00476 static const AVClass vfw_class = { 00477 .class_name = "VFW indev", 00478 .item_name = av_default_item_name, 00479 .option = options, 00480 .version = LIBAVUTIL_VERSION_INT, 00481 }; 00482 00483 AVInputFormat ff_vfwcap_demuxer = { 00484 "vfwcap", 00485 NULL_IF_CONFIG_SMALL("VFW video capture"), 00486 sizeof(struct vfw_ctx), 00487 NULL, 00488 vfw_read_header, 00489 vfw_read_packet, 00490 vfw_read_close, 00491 .flags = AVFMT_NOFILE, 00492 .priv_class = &vfw_class, 00493 };