Index: /pjproject/trunk/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c	(revision 5440)
+++ /pjproject/trunk/pjmedia/src/pjmedia-videodev/ffmpeg_dev.c	(revision 5441)
@@ -90,4 +90,5 @@
     pjmedia_vid_dev_param        param;
     AVFormatContext             *ff_fmt_ctx;
+    void			*frame_buf;
 } ffmpeg_stream;
 
@@ -162,5 +163,9 @@
 {
     PJ_UNUSED_ARG(ptr);
-    PJ_UNUSED_ARG(level);
+
+    /* Custom callback needs to filter log level by itself */
+    if (level > av_log_get_level())
+	return;
+
     vfprintf(stdout, fmt, vl);
 }
@@ -200,4 +205,5 @@
 #if LIBAVFORMAT_VER_AT_LEAST(53,2)
     /* Init ffmpeg dictionary */
+    /*
     snprintf(buf, sizeof(buf), "%d/%d", vfd->fps.num, vfd->fps.denum);
     av_dict_set(&format_opts, "framerate", buf, 0);
@@ -205,5 +211,5 @@
     av_dict_set(&format_opts, "video_size", buf, 0);
     av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(av_fmt), 0);
-
+    */
     /* Open capture stream */
     err = avformat_open_input(ctx, dev_name, ifmt, &format_opts);
@@ -283,4 +289,104 @@
 }
 
+
+#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
+    (defined(PJ_WIN64) && PJ_WIN64!=0)
+
+#ifdef _MSC_VER
+#   pragma warning(push, 3)
+#endif
+
+#define COBJMACROS
+#include <DShow.h>
+#pragma comment(lib, "Strmiids.lib")
+
+#ifdef _MSC_VER
+#   pragma warning(pop)
+#endif
+
+#define MAX_DEV_NAME_LEN 80
+
+static pj_status_t dshow_enum_devices(unsigned *dev_cnt,
+				      char dev_names[][MAX_DEV_NAME_LEN])
+{
+    unsigned max_cnt = *dev_cnt;
+    ICreateDevEnum *dev_enum = NULL;
+    IEnumMoniker *enum_cat = NULL;
+    IMoniker *moniker = NULL;
+    HRESULT hr;
+    ULONG fetched;
+    unsigned i = 0;
+
+    CoInitialize(0);
+
+    *dev_cnt = 0;
+    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
+                          CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
+                          (void**)&dev_enum);
+    if (FAILED(hr) ||
+        ICreateDevEnum_CreateClassEnumerator(dev_enum,
+            &CLSID_VideoInputDeviceCategory, &enum_cat, 0) != S_OK) 
+    {
+	PJ_LOG(4,(THIS_FILE, "Windows found no video input devices"));
+        if (dev_enum)
+            ICreateDevEnum_Release(dev_enum);
+
+	return PJ_SUCCESS;
+    }
+
+    while (IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK &&
+	   *dev_cnt < max_cnt)
+    {
+	(*dev_cnt)++;
+    }
+
+    if (*dev_cnt == 0) {
+        IEnumMoniker_Release(enum_cat);
+        ICreateDevEnum_Release(dev_enum);
+	return PJ_SUCCESS;
+    }
+
+    IEnumMoniker_Reset(enum_cat);
+    while (i < max_cnt &&
+	   IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK)
+    {
+        IPropertyBag *prop_bag;
+
+        hr = IMoniker_BindToStorage(moniker, 0, 0, &IID_IPropertyBag,
+                                    (void**)&prop_bag);
+        if (SUCCEEDED(hr)) {
+            VARIANT var_name;
+
+            VariantInit(&var_name);
+            hr = IPropertyBag_Read(prop_bag, L"FriendlyName", &var_name,
+				   NULL);
+            if (SUCCEEDED(hr) && var_name.bstrVal) {
+		char tmp[MAX_DEV_NAME_LEN] = {0};
+                WideCharToMultiByte(CP_ACP, 0, var_name.bstrVal,
+                                    (int)wcslen(var_name.bstrVal),
+                                    tmp, MAX_DEV_NAME_LEN, NULL, NULL);
+		pj_ansi_snprintf(dev_names[i++], MAX_DEV_NAME_LEN,
+				 "video=%s", tmp);
+            }
+            VariantClear(&var_name);
+            IPropertyBag_Release(prop_bag);
+        }
+        IMoniker_Release(moniker);
+    }
+
+    IEnumMoniker_Release(enum_cat);
+    ICreateDevEnum_Release(dev_enum);
+
+    PJ_LOG(4, (THIS_FILE, "DShow has %d devices:", *dev_cnt));
+    for (i = 0; i < *dev_cnt; ++i) {
+	PJ_LOG(4, (THIS_FILE, " %d: %s", (i+1), dev_names[i]));
+    }
+
+    return PJ_SUCCESS;
+}
+
+#endif /* PJ_WIN32 or PJ_WIN64 */
+
+
 /* API: refresh the list of devices */
 static pj_status_t ffmpeg_factory_refresh(pjmedia_vid_dev_factory *f)
@@ -288,8 +394,7 @@
     ffmpeg_factory *ff = (ffmpeg_factory*)f;
     AVInputFormat *p;
-    ffmpeg_dev_info *info;
 
     av_log_set_callback(&print_ffmpeg_log);
-    av_log_set_level(AV_LOG_DEBUG);
+    av_log_set_level(AV_LOG_ERROR);
 
     if (ff->dev_pool) {
@@ -298,74 +403,96 @@
     }
 
-    /* TODO: this should enumerate devices, now it enumerates host APIs */
     ff->dev_count = 0;
     ff->dev_pool = pj_pool_create(ff->pf, "ffmpeg_cap_dev", 500, 500, NULL);
 
-    p = av_iformat_next(NULL);
-    while (p) {
-	AVFormatContext *ctx;
-	AVCodecContext *codec = NULL;
-	pjmedia_format_id fmt_id;
-	pj_status_t status;
-	unsigned i;
-        
+    /* Iterate host APIs */
+    p = av_input_video_device_next(NULL);
+    while (p && ff->dev_count < MAX_DEV_CNT) {
+	char dev_names[MAX_DEV_CNT][MAX_DEV_NAME_LEN];
+	unsigned dev_cnt = MAX_DEV_CNT;
+	unsigned dev_idx;
+
 	if ((p->flags & AVFMT_NOFILE)==0 || p->read_probe) {
 	    goto next_format;
 	}
 
-        info = &ff->dev_info[ff->dev_count];
-        pj_bzero(info, sizeof(*info));
-        pj_ansi_strncpy(info->base.name, "default", 
-                        sizeof(info->base.name));
-        pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver),
-                         "%s (ffmpeg)", p->name);
-        info->base.dir = PJMEDIA_DIR_CAPTURE;
-        info->base.has_callback = PJ_FALSE;
-
-        info->host_api = p;
-
 #if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
     (defined(PJ_WIN64) && PJ_WIN64!=0)
-        info->def_devname = "0";
+	if (pj_ansi_strcmp(p->name, "dshow") == 0) {
+	    dshow_enum_devices(&dev_cnt, dev_names);
+	} else if (pj_ansi_strcmp(p->name, "vfwcap") == 0) {
+	    dev_cnt = 1;
+	    pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "0");
+	} else {
+	    dev_cnt = 0;
+	}
 #elif defined(PJ_LINUX) && PJ_LINUX!=0
-        info->def_devname = "/dev/video0";
+	dev_cnt = 1;
+	pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "/dev/video0");
+#else
+	dev_cnt = 0;
 #endif
 
-	ctx = avformat_alloc_context();
-	if (!ctx || avformat_open_input(&ctx, info->def_devname, p, NULL)!=0)
-	    goto next_format;
-
-	for(i = 0; i < ctx->nb_streams; i++) {
-	    if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-		codec = ctx->streams[i]->codec;
-		break;
+	/* Iterate devices (only DirectShow devices for now) */
+	for (dev_idx = 0; dev_idx < dev_cnt && ff->dev_count < MAX_DEV_CNT;
+	    ++dev_idx)
+	{
+	    ffmpeg_dev_info *info;
+	    AVFormatContext *ctx;
+	    AVCodecContext *codec = NULL;
+	    pjmedia_format_id fmt_id;
+	    pj_str_t dev_name;
+	    pj_status_t status;
+	    unsigned i;
+            
+	    ctx = avformat_alloc_context();
+	    if (!ctx || avformat_open_input(&ctx, dev_names[dev_idx], p, NULL)!=0)
+		continue;
+
+	    for(i = 0; i < ctx->nb_streams; i++) {
+		if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+		    codec = ctx->streams[i]->codec;
+		    break;
+		}
 	    }
+	    if (!codec) {
+		av_close_input_stream(ctx);
+		continue;
+	    }
+
+	    status = PixelFormat_to_pjmedia_format_id(codec->pix_fmt, &fmt_id);
+	    if (status != PJ_SUCCESS) {
+		av_close_input_stream(ctx);
+		continue;
+	    }
+
+	    info = &ff->dev_info[ff->dev_count++];
+	    pj_bzero(info, sizeof(*info));
+	    pj_ansi_strncpy(info->base.name, "default", 
+			    sizeof(info->base.name));
+	    pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver),
+			     "ffmpeg %s", p->name);
+	    
+	    pj_strdup2_with_null(ff->pool, &dev_name, dev_names[dev_idx]);
+	    info->def_devname = dev_name.ptr;
+	    info->base.dir = PJMEDIA_DIR_CAPTURE;
+	    info->base.has_callback = PJ_FALSE;
+
+	    info->host_api = p;
+
+	    /* Set supported formats */
+	    info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
+	    info->base.fmt_cnt = 1;
+	    for (i = 0; i < info->base.fmt_cnt; ++i) {
+		pjmedia_format *fmt = &info->base.fmt[i];
+		pjmedia_format_init_video(fmt, fmt_id,
+					  codec->width, codec->height, 15, 1);
+	    }
+
+	    av_close_input_stream(ctx);
 	}
-	if (!codec) {
-	    av_close_input_stream(ctx);
-	    goto next_format;
-	}
-
-	status = PixelFormat_to_pjmedia_format_id(codec->pix_fmt, &fmt_id);
-	if (status != PJ_SUCCESS) {
-	    av_close_input_stream(ctx);
-	    goto next_format;
-	}
-
-	/* Set supported formats */
-        info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
-        info->base.fmt_cnt = 1;
-        for (i = 0; i < info->base.fmt_cnt; ++i) {
-            pjmedia_format *fmt = &info->base.fmt[i];
-	    pjmedia_format_init_video(fmt, fmt_id,
-				      codec->width, codec->height, 15, 1);
-	}
-
-	av_close_input_stream(ctx);
-
-	ff->dev_count++;
 
 next_format:
-	p = av_iformat_next(p);
+	p = av_input_video_device_next(p);
     }
 
@@ -456,4 +583,19 @@
     pj_memcpy(&strm->param, param, sizeof(*param));
 
+    /* Allocate frame buffer */
+    {
+	const pjmedia_video_format_info *vfi;
+	pjmedia_video_apply_fmt_param vafp;
+
+	vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
+	if (!vfi) goto on_error;
+
+	pj_bzero(&vafp, sizeof(vafp));
+	vafp.size = param->fmt.det.vid.size;
+	vfi->apply_fmt(vfi, &vafp);
+
+	strm->frame_buf = pj_pool_alloc(pool, vafp.framebytes);
+    }
+
     /* Done */
     strm->base.op = &stream_op;
@@ -461,4 +603,8 @@
 
     return PJ_SUCCESS;
+
+on_error:
+    pj_pool_release(pool);
+    return PJMEDIA_EVID_INVCAP;
 }
 
@@ -532,5 +678,5 @@
 {
     ffmpeg_stream *strm = (ffmpeg_stream*)s;
-    AVPacket p;
+    AVPacket p = {0};
     int err;
 
@@ -543,6 +689,8 @@
     pj_bzero(frame, sizeof(*frame));
     frame->type = PJMEDIA_FRAME_TYPE_VIDEO;
-    frame->buf = p.data;
+    frame->buf = strm->frame_buf;
     frame->size = p.size;
+    pj_memcpy(frame->buf, p.data, p.size);
+    av_free_packet(&p);
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5440)
+++ /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5441)
@@ -491,5 +491,5 @@
     entry.level = level;
     entry.msg = string(data, len);
-    entry.threadId = (long)pj_thread_this();
+    entry.threadId = (long)(size_t)pj_thread_this();
     entry.threadName = string(pj_thread_get_name(pj_thread_this()));
 
