[FFmpeg-devel] [PATCH] VFW capture support
Michael Niedermayer
michaelni
Sat Mar 8 22:11:56 CET 2008
On Sat, Mar 08, 2008 at 05:46:38PM -0300, Ramiro Polla wrote:
> 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
> Index: libavformat/avformat.h
> ===================================================================
> --- libavformat/avformat.h (revision 12378)
> +++ libavformat/avformat.h (working copy)
> @@ -22,7 +22,7 @@
> #define FFMPEG_AVFORMAT_H
>
> #define LIBAVFORMAT_VERSION_MAJOR 52
> -#define LIBAVFORMAT_VERSION_MINOR 8
> +#define LIBAVFORMAT_VERSION_MINOR 9
> #define LIBAVFORMAT_VERSION_MICRO 0
>
> #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> @@ -508,6 +508,12 @@
> * demuxing: set by user
> */
> unsigned int max_index_size;
> +
> + /**
> + * Maximum ammount of memory in bytes to use for buffering frames that are
> + * obtained from real-time capture devices.
> + */
> + unsigned int max_buffer_size;
max_frame_buffer or max_picture_buffer or something like that as
max_buffer_size in a (de)muxer context really is intuitively something
different.
the rest looks ok
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Freedom in capitalist society always remains about the same as it was in
ancient Greek republics: Freedom for slave owners. -- Vladimir Lenin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080308/3c624e0c/attachment.pgp>
More information about the ffmpeg-devel
mailing list