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