[FFmpeg-devel] [PATCH] VFW capture support

Ramiro Polla ramiro
Sat Mar 8 21:46:38 CET 2008


Hello Michael,

[...]
>> Mans suggested using a ring buffer, a semaphore and dropping frames instead 
>> of using the mutexes and events and piling up every single frame.
>>
>> If it is preferred to drop frames, is there an existing option that could 
>> be used to set the maximum amount of memory/time buffered?
> 
> Droping frames might be more user friendly. But simply droping when the buffer
> is full is not optimal. Reason being that with a nearly full buffer and
> some short drop in available resources (cronjob or whatever) several frames
> could be droped in a row.
> What should be done is that as the buffer becomes more full more frames
> should be droped, so for example maybe with the buffer 0-50% full no
> frame drops would happen, with 62% every 4th frame would be droped, with
> 75% every 2nd frame would be droped, 87% 3 out of 4 frames would be droped
> ...
> The trick here is to keep the droped frames evenly distributed.
> There are many ways this can be implemnted, the simplest i could think of is
> 
> const static uint8_t score[4]={62,87,75,100};
> if(score[frame_num%4] < buffer_fullness)
>     drop;

Implemented. I added an option to AVFormatContext in a separate patch.

[...]

>> static enum PixelFormat vfw_pixfmt(DWORD biCompression)
>> {
>>     switch(biCompression) {
>>     case MKTAG('Y', 'U', 'Y', '2'):
>>         return PIX_FMT_YUYV422;
> 
>>     case BI_RGB:
>>         return PIX_FMT_BGR24;
> 
> This isnt correct or is it? BI_RGB just says RGB but not which one or am i
> remembering this wrong?

It is more complete right now and working correct for RGB. I didn't test 
bit depths 1, 4, and 8 since I didn't find any device to test and wasn't 
able to simulate them either.

Why I must set RGB sometimes and BGR other times is a mistery for me, 
but lots of Windows' internals are a mistery anyways.

> [...]
>> static LRESULT CALLBACK videostream_cb(HWND hwnd, LPVIDEOHDR vdhdr)
>> {
>>     struct vfw_ctx *ctx;
>>     AVPacketList *pktl, *pktl_next;
>>
>>     ctx = (struct vfw_ctx *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
>>
>> #ifdef VFW_DEBUG
>>     dump_videohdr(ctx->s, vdhdr);
>> #endif
>>
>>     WaitForSingleObject(ctx->mutex, INFINITE);
>>
>>     pktl_next = av_mallocz(sizeof(AVPacketList));
>>     if(!pktl_next)
>>         return FALSE;
>>
>>     if(av_new_packet(&pktl_next->pkt, vdhdr->dwBytesUsed) < 0) {
>>         av_free(pktl_next);
>>         return FALSE;
>>     }
> 
> What will happen with the mutex if you just return here?

Fixed.

>>     pktl_next->pkt.pts = vdhdr->dwTimeCaptured;
>>     memcpy(pktl_next->pkt.data, vdhdr->lpData, vdhdr->dwBytesUsed);
>>
> 
>>     for(pktl = ctx->pktl ; pktl && pktl->next ; pktl = pktl->next);
>>     if(!pktl)
>>         ctx->pktl = pktl_next;
>>     else
>>         pktl->next = pktl_next;
> 
> following is simpler:
> 
> for(plast_pktl= &ctx->pktl ; *plast_pktl ; plast_pktl= &(*plast_pktl)->next);
> *plast_pktl= pktl_next

Indeed.

>>     SetEvent(ctx->event);
>>     ReleaseMutex(ctx->mutex);
>>
>>     return TRUE;
>> }
>>
>> static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap)
>> {
>>     struct vfw_ctx *ctx = s->priv_data;
>>     AVCodecContext *codec;
>>     AVStream *st;
>>     int devnum;
>>     int bisize;
>>     BITMAPINFO *bi;
>>     CAPTUREPARMS cparms;
>>     DWORD biCompression;
>>     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;
>>     }
>>
>> #ifdef VFW_DEBUG
>>     ctx->s = s;
>> #endif
>>
>>     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;
>>     }
>>
>>     /* If atoi fails, devnum==0 and the default device is used */
>>     devnum = atoi(s->filename);
>>
>>     ret = SendMessage(ctx->hwnd, WM_CAP_DRIVER_CONNECT, devnum, 0);
>>     if(!ret) {
>>         av_log(s, AV_LOG_ERROR, "Could not connect to device.\n");
>>         return AVERROR(ENODEV);
>>     }
>>
>>     SendMessage(ctx->hwnd, WM_CAP_SET_OVERLAY, 0, 0);
>>     SendMessage(ctx->hwnd, WM_CAP_SET_PREVIEW, 0, 0);
>>
>>     ret = SendMessage(ctx->hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0,
>>                       (LPARAM) videostream_cb);
>>     if(!ret)
>>         return AVERROR_IO;
>>
>>     SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR) ctx);
>>
>>     st = av_new_stream(s, 0);
>>     if(!st)
>>         return AVERROR_NOMEM;
>>
>>     /* Set video format */
>>     bisize = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0);
>>     if(!bisize)
>>         return AVERROR_IO;
>>     bi = av_malloc(bisize);
>>     if(!bi)
>>         return AVERROR_NOMEM;
>>     ret = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, bisize, (LPARAM) bi);
>>     if(!ret) {
>>         av_free(bi);
>>         return AVERROR_IO;
>>     }
>>
>>     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;
>>
>>     ret = SendMessage(ctx->hwnd, WM_CAP_SET_VIDEOFORMAT, bisize, (LPARAM) bi);
>>     if(!ret) {
>>         av_log(s, AV_LOG_ERROR, "Could not set Video Format.\n");
>>         av_free(bi);
>>         return AVERROR_IO;
>>     }
>>
>>     biCompression = bi->bmiHeader.biCompression;
>>
>>     av_free(bi);
>>
>>     /* Set sequence setup */
>>     ret = SendMessage(ctx->hwnd, WM_CAP_GET_SEQUENCE_SETUP, sizeof(cparms),
>>                       (LPARAM) &cparms);
>>     if(!ret)
>>         return AVERROR_IO;
>>
>>     dump_captureparms(s, &cparms);
>>
>>     cparms.fYield = 1; // Spawn a background thread
>>     cparms.dwRequestMicroSecPerFrame =
>>                                (ap->time_base.num*1000000) / ap->time_base.den;
>>     cparms.fAbortLeftMouse = 0;
>>     cparms.fAbortRightMouse = 0;
>>     cparms.fCaptureAudio = 0;
>>     cparms.vKeyAbort = 0;
>>
>>     ret = SendMessage(ctx->hwnd, WM_CAP_SET_SEQUENCE_SETUP, sizeof(cparms),
>>                       (LPARAM) &cparms);
>>     if(!ret)
>>         return AVERROR_IO;
>>
>>     codec = st->codec;
>>     codec->time_base = ap->time_base;
>>     codec->codec_type = CODEC_TYPE_VIDEO;
>>     codec->width = width;
>>     codec->height = height;
>>     codec->codec_id = CODEC_ID_RAWVIDEO;
>>     codec->pix_fmt = vfw_pixfmt(biCompression);
>>
>>     av_set_pts_info(st, 32, 1, 1000);
>>
>>     if(codec->pix_fmt == -1) {
>>         av_log(s, AV_LOG_ERROR, "Unknown compression type."
>>                          "Please report verbose (-v 99) debug information.\n");
>>         return AVERROR_PATCHWELCOME;
>>     }
>>
>>     ctx->mutex = CreateMutex(NULL, 0, NULL);
>>     ctx->event = CreateEvent(NULL, 1, 0, NULL);
>>
>>     ret = SendMessage(ctx->hwnd, WM_CAP_SEQUENCE_NOFILE, 0, 0);
>>     if(!ret)
>>         return AVERROR_IO;
> 
> I suspect that quite a few of the returns cause various leaks, that is
> the stuff from vfw_read_close() is missing.

I think it should be fine now.

Ramiro Polla
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: rtbufsize.diff
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080308/1748ef29/attachment.asc>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vfwcap.c
Type: text/x-csrc
Size: 13433 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080308/1748ef29/attachment.c>



More information about the ffmpeg-devel mailing list