From 7cd61abbb0f4467dcdabf2a0334272702695174e Mon Sep 17 00:00:00 2001 From: Jinhyung Jo Date: Wed, 28 Mar 2012 18:35:50 +0900 Subject: [PATCH] [Title] changed thread API to use(pthread -> qemu-thread) & removed VS2010 dependency. [Type] Enhancement [Module] Emulator/Camera [Priority] Minor [CQ#] [Redmine#] [Problem] [Cause] [Solution] [TestCase] --- tizen/src/Makefile.tizen | 6 +- tizen/src/hw/maru_camera_common.h | 224 +- tizen/src/hw/maru_camera_common_pci.c | 502 ++-- tizen/src/hw/maru_camera_linux_pci.c | 1313 +++++----- tizen/src/hw/maru_camera_win32_interface.h | 932 +++++++ tizen/src/hw/maru_camera_win32_pci.c | 2748 ++++++++++++++------ 6 files changed, 3946 insertions(+), 1779 deletions(-) create mode 100644 tizen/src/hw/maru_camera_win32_interface.h diff --git a/tizen/src/Makefile.tizen b/tizen/src/Makefile.tizen index b6775b8648..56c32ec869 100755 --- a/tizen/src/Makefile.tizen +++ b/tizen/src/Makefile.tizen @@ -79,10 +79,12 @@ obj-i386-y += maru_touchscreen.o obj-i386-$(CONFIG_PCI) += maru_camera_common_pci.o obj-i386-$(CONFIG_LINUX) += maru_camera_linux_pci.o obj-i386-$(CONFIG_WIN32) += maru_camera_win32_pci.o -# libs for maru camera on linux host -ifdef CONFIG_LINUX +ifdef CONFIG_LINUX # libs for maru camera on linux host LIBS += -lv4l2 -lv4lconvert endif +ifdef CONFIG_WIN32 # libs for maru camera on windows host +LIBS += -lole32 -loleaut32 -luuid -lstrmiids +endif # maru skin diff --git a/tizen/src/hw/maru_camera_common.h b/tizen/src/hw/maru_camera_common.h index 853b8a65f8..5d5cf7a28c 100644 --- a/tizen/src/hw/maru_camera_common.h +++ b/tizen/src/hw/maru_camera_common.h @@ -1,116 +1,108 @@ -/* - * Common header of MARU Virtual Camera device. - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: - * JinHyung Jo - * YeongKyoon Lee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - -#ifndef _MARU_CAMERA_COMMON_H_ -#define _MARU_CAMERA_COMMON_H_ - -#include "pci.h" -#include - -#define MARUCAM_MAX_PARAM 20 - -/* must sync with GUEST camera_driver */ -#define MARUCAM_CMD_INIT 0x00 -#define MARUCAM_CMD_OPEN 0x04 -#define MARUCAM_CMD_CLOSE 0x08 -#define MARUCAM_CMD_ISSTREAM 0x0C -#define MARUCAM_CMD_START_PREVIEW 0x10 -#define MARUCAM_CMD_STOP_PREVIEW 0x14 -#define MARUCAM_CMD_S_PARAM 0x18 -#define MARUCAM_CMD_G_PARAM 0x1C -#define MARUCAM_CMD_ENUM_FMT 0x20 -#define MARUCAM_CMD_TRY_FMT 0x24 -#define MARUCAM_CMD_S_FMT 0x28 -#define MARUCAM_CMD_G_FMT 0x2C -#define MARUCAM_CMD_QCTRL 0x30 -#define MARUCAM_CMD_S_CTRL 0x34 -#define MARUCAM_CMD_G_CTRL 0x38 -#define MARUCAM_CMD_ENUM_FSIZES 0x3C -#define MARUCAM_CMD_ENUM_FINTV 0x40 -#define MARUCAM_CMD_S_DATA 0x44 -#define MARUCAM_CMD_G_DATA 0x48 -#define MARUCAM_CMD_CLRIRQ 0x4C -#define MARUCAM_CMD_DATACLR 0x50 -#define MARUCAM_CMD_REQFRAME 0x54 - -typedef struct MaruCamState MaruCamState; -typedef struct MaruCamThreadInfo MaruCamThreadInfo; -typedef struct MaruCamParam MaruCamParam; - -struct MaruCamParam { - uint32_t top; - uint32_t retVal; - uint32_t errCode; - uint32_t stack[MARUCAM_MAX_PARAM]; -}; - -struct MaruCamThreadInfo { - MaruCamState* state; - MaruCamParam* param; - - pthread_t thread_id; - pthread_cond_t thread_cond; - pthread_mutex_t mutex_lock; -}; - -struct MaruCamState { - PCIDevice dev; - - void *vaddr; /* vram ptr */ - uint32_t streamon; - uint32_t buf_size; - uint32_t req_frame; - - MemoryRegion vram; - MemoryRegion mmio; - - MaruCamThreadInfo *thread; -}; - -/* ----------------------------------------------------------------------------- */ -/* Fucntion prototype */ -/* ----------------------------------------------------------------------------- */ -void marucam_device_init(MaruCamState *state); -void marucam_device_open(MaruCamState *state); -void marucam_device_close(MaruCamState *state); -void marucam_device_start_preview(MaruCamState *state); -void marucam_device_stop_preview(MaruCamState *state); -void marucam_device_s_param(MaruCamState *state); -void marucam_device_g_param(MaruCamState *state); -void marucam_device_s_fmt(MaruCamState *state); -void marucam_device_g_fmt(MaruCamState *state); -void marucam_device_try_fmt(MaruCamState *state); -void marucam_device_enum_fmt(MaruCamState *state); -void marucam_device_qctrl(MaruCamState *state); -void marucam_device_s_ctrl(MaruCamState *state); -void marucam_device_g_ctrl(MaruCamState *state); -void marucam_device_enum_fsizes(MaruCamState *state); -void marucam_device_enum_fintv(MaruCamState *state); - - -#endif /* _MARU_CAMERA_COMMON_H_ */ +/* + * Common header of MARU Virtual Camera device. + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef _MARU_CAMERA_COMMON_H_ +#define _MARU_CAMERA_COMMON_H_ + +#include "pci.h" +#include "qemu-thread.h" + +#define MARUCAM_MAX_PARAM 20 + +/* must sync with GUEST camera_driver */ +#define MARUCAM_CMD_INIT 0x00 +#define MARUCAM_CMD_OPEN 0x04 +#define MARUCAM_CMD_CLOSE 0x08 +#define MARUCAM_CMD_ISSTREAM 0x0C +#define MARUCAM_CMD_START_PREVIEW 0x10 +#define MARUCAM_CMD_STOP_PREVIEW 0x14 +#define MARUCAM_CMD_S_PARAM 0x18 +#define MARUCAM_CMD_G_PARAM 0x1C +#define MARUCAM_CMD_ENUM_FMT 0x20 +#define MARUCAM_CMD_TRY_FMT 0x24 +#define MARUCAM_CMD_S_FMT 0x28 +#define MARUCAM_CMD_G_FMT 0x2C +#define MARUCAM_CMD_QCTRL 0x30 +#define MARUCAM_CMD_S_CTRL 0x34 +#define MARUCAM_CMD_G_CTRL 0x38 +#define MARUCAM_CMD_ENUM_FSIZES 0x3C +#define MARUCAM_CMD_ENUM_FINTV 0x40 +#define MARUCAM_CMD_S_DATA 0x44 +#define MARUCAM_CMD_G_DATA 0x48 +#define MARUCAM_CMD_CLRIRQ 0x4C +#define MARUCAM_CMD_DATACLR 0x50 +#define MARUCAM_CMD_REQFRAME 0x54 + +typedef struct MaruCamState MaruCamState; +typedef struct MaruCamParam MaruCamParam; + +struct MaruCamParam { + uint32_t top; + uint32_t retVal; + uint32_t errCode; + uint32_t stack[MARUCAM_MAX_PARAM]; +}; + +struct MaruCamState { + PCIDevice dev; + MaruCamParam *param; + QemuThread thread_id; + QemuMutex thread_mutex;; + QemuCond thread_cond; + + void *vaddr; /* vram ptr */ + uint32_t streamon; + uint32_t buf_size; + uint32_t req_frame; + + MemoryRegion vram; + MemoryRegion mmio; +}; + +/* ----------------------------------------------------------------------------- */ +/* Fucntion prototype */ +/* ----------------------------------------------------------------------------- */ +void marucam_device_init(MaruCamState *state); +void marucam_device_open(MaruCamState *state); +void marucam_device_close(MaruCamState *state); +void marucam_device_start_preview(MaruCamState *state); +void marucam_device_stop_preview(MaruCamState *state); +void marucam_device_s_param(MaruCamState *state); +void marucam_device_g_param(MaruCamState *state); +void marucam_device_s_fmt(MaruCamState *state); +void marucam_device_g_fmt(MaruCamState *state); +void marucam_device_try_fmt(MaruCamState *state); +void marucam_device_enum_fmt(MaruCamState *state); +void marucam_device_qctrl(MaruCamState *state); +void marucam_device_s_ctrl(MaruCamState *state); +void marucam_device_g_ctrl(MaruCamState *state); +void marucam_device_enum_fsizes(MaruCamState *state); +void marucam_device_enum_fintv(MaruCamState *state); + + +#endif /* _MARU_CAMERA_COMMON_H_ */ diff --git a/tizen/src/hw/maru_camera_common_pci.c b/tizen/src/hw/maru_camera_common_pci.c index f6eccd04e0..5ee1df784b 100644 --- a/tizen/src/hw/maru_camera_common_pci.c +++ b/tizen/src/hw/maru_camera_common_pci.c @@ -1,253 +1,249 @@ -/* - * Common implementation of MARU Virtual Camera device by PCI bus. - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: - * JinHyung Jo - * YeongKyoon Lee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - - -#include -#include -#include -#include -#include -#include - -#include "qemu-common.h" -#include "cpu-common.h" - -#include "pci.h" -#include "pci_ids.h" -#include "maru_pci_ids.h" - -#include "maru_camera_common.h" -#include "tizen/src/debug_ch.h" - -MULTI_DEBUG_CHANNEL(tizen, camera_pci); - -#define MARU_PCI_CAMERA_DEVICE_NAME "maru_camera_pci" - -#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) // 4MB -#define MARUCAM_REG_SIZE (256) // 64 * 4 - -/* - * I/O functions - */ -static inline uint32_t marucam_mmio_read(void *opaque, target_phys_addr_t offset) -{ - uint32_t ret = 0; - MaruCamState *state = (MaruCamState*)opaque; - - switch (offset & 0xFF) { - case MARUCAM_CMD_ISSTREAM: - pthread_mutex_lock(&state->thread->mutex_lock); - ret = state->streamon; - pthread_mutex_unlock(&state->thread->mutex_lock); - break; - case MARUCAM_CMD_G_DATA: - ret = state->thread->param->stack[state->thread->param->top++]; - break; - case MARUCAM_CMD_OPEN: - case MARUCAM_CMD_CLOSE: - case MARUCAM_CMD_START_PREVIEW: - case MARUCAM_CMD_STOP_PREVIEW: - case MARUCAM_CMD_S_PARAM: - case MARUCAM_CMD_G_PARAM: - case MARUCAM_CMD_ENUM_FMT: - case MARUCAM_CMD_TRY_FMT: - case MARUCAM_CMD_S_FMT: - case MARUCAM_CMD_G_FMT: - case MARUCAM_CMD_QCTRL: - case MARUCAM_CMD_S_CTRL: - case MARUCAM_CMD_G_CTRL: - case MARUCAM_CMD_ENUM_FSIZES: - case MARUCAM_CMD_ENUM_FINTV: - ret = state->thread->param->errCode; - state->thread->param->errCode = 0; - break; - default: - WARN("Not supported command!!\n"); - break; - } - return ret; -} - -static inline void marucam_mmio_write(void *opaque, target_phys_addr_t offset, uint32_t value) -{ - MaruCamState *state = (MaruCamState*)opaque; - - switch(offset & 0xFF) { - case MARUCAM_CMD_OPEN: - marucam_device_open(state); - break; - case MARUCAM_CMD_CLOSE: - marucam_device_close(state); - break; - case MARUCAM_CMD_START_PREVIEW: - marucam_device_start_preview(state); - break; - case MARUCAM_CMD_STOP_PREVIEW: - marucam_device_stop_preview(state); - break; - case MARUCAM_CMD_S_PARAM: - marucam_device_s_param(state); - break; - case MARUCAM_CMD_G_PARAM: - marucam_device_g_param(state); - break; - case MARUCAM_CMD_ENUM_FMT: - marucam_device_enum_fmt(state); - break; - case MARUCAM_CMD_TRY_FMT: - marucam_device_try_fmt(state); - break; - case MARUCAM_CMD_S_FMT: - marucam_device_s_fmt(state); - break; - case MARUCAM_CMD_G_FMT: - marucam_device_g_fmt(state); - break; - case MARUCAM_CMD_QCTRL: - marucam_device_qctrl(state); - break; - case MARUCAM_CMD_S_CTRL: - marucam_device_s_ctrl(state); - break; - case MARUCAM_CMD_G_CTRL: - marucam_device_g_ctrl(state); - break; - case MARUCAM_CMD_ENUM_FSIZES: - marucam_device_enum_fsizes(state); - break; - case MARUCAM_CMD_ENUM_FINTV: - marucam_device_enum_fintv(state); - break; - case MARUCAM_CMD_S_DATA: - state->thread->param->stack[state->thread->param->top++] = value; - break; - case MARUCAM_CMD_DATACLR: - memset(state->thread->param, 0, sizeof(MaruCamParam)); - break; - case MARUCAM_CMD_CLRIRQ: - qemu_irq_lower(state->dev.irq[2]); - break; - case MARUCAM_CMD_REQFRAME: - pthread_mutex_lock(&state->thread->mutex_lock); - state->req_frame = value + 1; - pthread_mutex_unlock(&state->thread->mutex_lock); - break; - default: - WARN("Not supported command!!\n"); - break; - } -} - -static const MemoryRegionOps maru_camera_mmio_ops = { - .old_mmio = { - .read = { - marucam_mmio_read, - marucam_mmio_read, - marucam_mmio_read, - }, - .write = { - marucam_mmio_write, - marucam_mmio_write, - marucam_mmio_write, - }, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -/* - * Initialization function - */ -static int marucam_initfn(PCIDevice *dev) -{ - MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev); - uint8_t *pci_conf = s->dev.config; - MaruCamThreadInfo *thread; - MaruCamParam *param; - - pci_config_set_interrupt_pin(pci_conf, 0x03); - - memory_region_init_ram(&s->vram, NULL, "marucamera.ram", MARUCAM_MEM_SIZE); - s->vaddr = memory_region_get_ram_ptr(&s->vram); - - memory_region_init_io (&s->mmio, &maru_camera_mmio_ops, s, "maru-camera-mmio", MARUCAM_REG_SIZE); - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); - pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); - - /* for worker thread */ - thread = (MaruCamThreadInfo*)g_malloc0(sizeof(MaruCamThreadInfo)); - param = (MaruCamParam*)g_malloc0(sizeof(MaruCamParam)); - - thread->state = s; - thread->param = param; - s->thread = thread; - - marucam_device_init(s); - - return 0; -} - -/* - * Termination function - */ -static int marucam_exitfn(PCIDevice *dev) -{ - MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev); - - g_free((gpointer)s->thread->param); - g_free((gpointer)s->thread); - - memory_region_destroy (&s->vram); - memory_region_destroy (&s->mmio); - return 0; -} - -int maru_camera_pci_init(PCIBus *bus) -{ - INFO("[%s] camera device was initialized.\n", __func__); - pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME); - return 0; -} - -static PCIDeviceInfo maru_camera_info = { - .qdev.name = MARU_PCI_CAMERA_DEVICE_NAME, - .qdev.desc = "MARU Virtual Camera device for Tizen emulator", - .qdev.size = sizeof(MaruCamState), - .no_hotplug = 1, - .init = marucam_initfn, - .exit = marucam_exitfn, - .vendor_id = PCI_VENDOR_ID_TIZEN, - .device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA, - .class_id = PCI_CLASS_OTHERS, -}; - -static void maru_camera_pci_register(void) -{ - pci_qdev_register(&maru_camera_info); -} - -device_init(maru_camera_pci_register); +/* + * Common implementation of MARU Virtual Camera device by PCI bus. + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "qemu-common.h" +#include "cpu-common.h" + +#include "pci.h" +#include "pci_ids.h" +#include "maru_pci_ids.h" + +#include "maru_camera_common.h" +#include "tizen/src/debug_ch.h" + +MULTI_DEBUG_CHANNEL(tizen, camera_pci); + +#define MARU_PCI_CAMERA_DEVICE_NAME "maru_camera_pci" + +#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) // 4MB +#define MARUCAM_REG_SIZE (256) // 64 * 4 + +/* + * I/O functions + */ +static inline uint32_t marucam_mmio_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret = 0; + MaruCamState *state = (MaruCamState*)opaque; + + switch (offset & 0xFF) { + case MARUCAM_CMD_ISSTREAM: + qemu_mutex_lock(&state->thread_mutex); + ret = state->streamon; + qemu_mutex_unlock(&state->thread_mutex); + break; + case MARUCAM_CMD_G_DATA: + ret = state->param->stack[state->param->top++]; + break; + case MARUCAM_CMD_OPEN: + case MARUCAM_CMD_CLOSE: + case MARUCAM_CMD_START_PREVIEW: + case MARUCAM_CMD_STOP_PREVIEW: + case MARUCAM_CMD_S_PARAM: + case MARUCAM_CMD_G_PARAM: + case MARUCAM_CMD_ENUM_FMT: + case MARUCAM_CMD_TRY_FMT: + case MARUCAM_CMD_S_FMT: + case MARUCAM_CMD_G_FMT: + case MARUCAM_CMD_QCTRL: + case MARUCAM_CMD_S_CTRL: + case MARUCAM_CMD_G_CTRL: + case MARUCAM_CMD_ENUM_FSIZES: + case MARUCAM_CMD_ENUM_FINTV: + ret = state->param->errCode; + state->param->errCode = 0; + break; + default: + WARN("Not supported command!!\n"); + break; + } + return ret; +} + +static inline void marucam_mmio_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + MaruCamState *state = (MaruCamState*)opaque; + + switch(offset & 0xFF) { + case MARUCAM_CMD_OPEN: + marucam_device_open(state); + break; + case MARUCAM_CMD_CLOSE: + marucam_device_close(state); + break; + case MARUCAM_CMD_START_PREVIEW: + marucam_device_start_preview(state); + break; + case MARUCAM_CMD_STOP_PREVIEW: + marucam_device_stop_preview(state); + break; + case MARUCAM_CMD_S_PARAM: + marucam_device_s_param(state); + break; + case MARUCAM_CMD_G_PARAM: + marucam_device_g_param(state); + break; + case MARUCAM_CMD_ENUM_FMT: + marucam_device_enum_fmt(state); + break; + case MARUCAM_CMD_TRY_FMT: + marucam_device_try_fmt(state); + break; + case MARUCAM_CMD_S_FMT: + marucam_device_s_fmt(state); + break; + case MARUCAM_CMD_G_FMT: + marucam_device_g_fmt(state); + break; + case MARUCAM_CMD_QCTRL: + marucam_device_qctrl(state); + break; + case MARUCAM_CMD_S_CTRL: + marucam_device_s_ctrl(state); + break; + case MARUCAM_CMD_G_CTRL: + marucam_device_g_ctrl(state); + break; + case MARUCAM_CMD_ENUM_FSIZES: + marucam_device_enum_fsizes(state); + break; + case MARUCAM_CMD_ENUM_FINTV: + marucam_device_enum_fintv(state); + break; + case MARUCAM_CMD_S_DATA: + state->param->stack[state->param->top++] = value; + break; + case MARUCAM_CMD_DATACLR: + memset(state->param, 0, sizeof(MaruCamParam)); + break; + case MARUCAM_CMD_CLRIRQ: + qemu_irq_lower(state->dev.irq[2]); + break; + case MARUCAM_CMD_REQFRAME: + qemu_mutex_lock(&state->thread_mutex); + state->req_frame = value + 1; + qemu_mutex_unlock(&state->thread_mutex); + break; + default: + WARN("Not supported command!!\n"); + break; + } +} + +static const MemoryRegionOps maru_camera_mmio_ops = { + .old_mmio = { + .read = { + marucam_mmio_read, + marucam_mmio_read, + marucam_mmio_read, + }, + .write = { + marucam_mmio_write, + marucam_mmio_write, + marucam_mmio_write, + }, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +/* + * Initialization function + */ +static int marucam_initfn(PCIDevice *dev) +{ + MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev); + uint8_t *pci_conf = s->dev.config; + + pci_config_set_interrupt_pin(pci_conf, 0x03); + + memory_region_init_ram(&s->vram, NULL, "marucamera.ram", MARUCAM_MEM_SIZE); + s->vaddr = memory_region_get_ram_ptr(&s->vram); + + memory_region_init_io (&s->mmio, &maru_camera_mmio_ops, s, "maru-camera-mmio", MARUCAM_REG_SIZE); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); + + /* for worker thread */ + s->param = (MaruCamParam*)g_malloc0(sizeof(MaruCamParam)); + qemu_cond_init(&s->thread_cond); + qemu_mutex_init(&s->thread_mutex); + + marucam_device_init(s); + + return 0; +} + +/* + * Termination function + */ +static int marucam_exitfn(PCIDevice *dev) +{ + MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev); + + g_free((gpointer)s->param); + qemu_cond_destroy(&s->thread_cond); + qemu_mutex_destroy(&s->thread_mutex); + + memory_region_destroy (&s->vram); + memory_region_destroy (&s->mmio); + return 0; +} + +int maru_camera_pci_init(PCIBus *bus) +{ + INFO("[%s] camera device was initialized.\n", __func__); + pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME); + return 0; +} + +static PCIDeviceInfo maru_camera_info = { + .qdev.name = MARU_PCI_CAMERA_DEVICE_NAME, + .qdev.desc = "MARU Virtual Camera device for Tizen emulator", + .qdev.size = sizeof(MaruCamState), + .no_hotplug = 1, + .init = marucam_initfn, + .exit = marucam_exitfn, + .vendor_id = PCI_VENDOR_ID_TIZEN, + .device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA, + .class_id = PCI_CLASS_OTHERS, +}; + +static void maru_camera_pci_register(void) +{ + pci_qdev_register(&maru_camera_info); +} + +device_init(maru_camera_pci_register); diff --git a/tizen/src/hw/maru_camera_linux_pci.c b/tizen/src/hw/maru_camera_linux_pci.c index 2bdb16b2c0..0e86dc2414 100644 --- a/tizen/src/hw/maru_camera_linux_pci.c +++ b/tizen/src/hw/maru_camera_linux_pci.c @@ -1,664 +1,649 @@ -/* - * Implementation of MARU Virtual Camera device by PCI bus on Linux. - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: - * JinHyung Jo - * YeongKyoon Lee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - -#include "qemu-common.h" -#include "qemu-common.h" -#include "maru_camera_common.h" -#include "pci.h" -#include "kvm.h" -#include "tizen/src/debug_ch.h" - -#include - -#include -#include - -MULTI_DEBUG_CHANNEL(tizen, camera_linux); - -static int v4l2_fd; -static int convert_trial; - -static struct v4l2_format dst_fmt; - -static int xioctl(int fd, int req, void *arg) -{ - int r; - - do { - r = v4l2_ioctl(fd, req, arg); - } while ( r < 0 && errno == EINTR); - - return r; -} - -#define MARUCAM_CTRL_VALUE_MAX 20 -#define MARUCAM_CTRL_VALUE_MIN 1 -#define MARUCAM_CTRL_VALUE_MID 10 -#define MARUCAM_CTRL_VALUE_STEP 1 - -struct marucam_qctrl { - uint32_t id; - uint32_t hit; - int32_t min; - int32_t max; - int32_t step; - int32_t init_val; -}; - -static struct marucam_qctrl qctrl_tbl[] = { - { V4L2_CID_BRIGHTNESS, 0, }, - { V4L2_CID_CONTRAST, 0, }, - { V4L2_CID_SATURATION,0, }, - { V4L2_CID_SHARPNESS, 0, }, -}; - -static void marucam_reset_controls(void) -{ - uint32_t i; - for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) { - if (qctrl_tbl[i].hit) { - struct v4l2_control ctrl = {0,}; - ctrl.id = qctrl_tbl[i].id; - ctrl.value = qctrl_tbl[i].init_val; - if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) { - ERR("failed to set video control value while reset values : %s\n", strerror(errno)); - } - } - } -} - -static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value) -{ - double rate = 0.0; - int32_t dist = 0, ret = 0; - - dist = max - min; - - if (dist < MARUCAM_CTRL_VALUE_MAX) { - rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; - ret = min + (int32_t)(value / rate); - } else { - rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; - ret = min + (int32_t)(rate * value); - } - return ret; -} - -static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value) -{ - double rate = 0.0; - int32_t dist = 0, ret = 0; - - dist = max - min; - - if (dist < MARUCAM_CTRL_VALUE_MAX) { - rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; - ret = (int32_t)((double)(value - min) * rate); - } else { - rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; - ret = (int32_t)((double)(value - min) / rate); - } - - return ret; -} - -static int __v4l2_grab(MaruCamState *state) -{ - fd_set fds; - static uint32_t index = 0; - struct timeval tv; - void *buf; - int ret; - - FD_ZERO(&fds); - FD_SET(v4l2_fd, &fds); - - tv.tv_sec = 2; - tv.tv_usec = 0; - - ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv); - if ( ret < 0) { - if (errno == EINTR) - return 0; - ERR("select : %s\n", strerror(errno)); - return -1; - } - if (!ret) { - WARN("Timed out\n"); - return 0; - } - - if (!v4l2_fd) { - WARN("file descriptor is closed or not opened \n"); - return -1; - } - - buf = state->vaddr + (state->buf_size * index); - ret = v4l2_read(v4l2_fd, buf, state->buf_size); - if ( ret < 0) { - switch (errno) { - case EINVAL: - case ENOMEM: - ERR("v4l2_read failed : %s\n", strerror(errno)); - return -1; - case EAGAIN: - case EIO: - case EINTR: - default: - if (convert_trial-- == -1) { - ERR("Try count for v4l2_read is exceeded\n"); - return -1; - } - return 0; - } - } - - index = !index; - - pthread_mutex_lock(&state->thread->mutex_lock); - if (state->streamon) { - if (state->req_frame) { - qemu_irq_raise(state->dev.irq[2]); - state->req_frame = 0; - } - ret = 1; - } else { - ret = -1; - } - pthread_mutex_unlock(&state->thread->mutex_lock); - - return ret; -} - -// Worker thread -static void *marucam_worker_thread(void *thread_param) -{ - MaruCamThreadInfo* thread = (MaruCamThreadInfo*)thread_param; - -wait_worker_thread: - pthread_mutex_lock(&thread->mutex_lock); - thread->state->streamon = 0; - convert_trial = 10; - pthread_cond_wait(&thread->thread_cond, &thread->mutex_lock); - pthread_mutex_unlock(&thread->mutex_lock); - INFO("Streaming on ......\n"); - - while (1) - { - pthread_mutex_lock(&thread->mutex_lock); - if (thread->state->streamon) { - pthread_mutex_unlock(&thread->mutex_lock); - if (__v4l2_grab(thread->state) < 0) { - INFO("...... Streaming off\n"); - goto wait_worker_thread; - } - } else { - pthread_mutex_unlock(&thread->mutex_lock); - goto wait_worker_thread; - } - } - pthread_exit(0); -} - -void marucam_device_init(MaruCamState* state) -{ - MaruCamThreadInfo *thread = state->thread; - - if (pthread_cond_init(&thread->thread_cond, NULL)) { - ERR("failed to initialize thread condition\n"); - exit(61); - } - if (pthread_mutex_init(&thread->mutex_lock, NULL)) { - ERR("failed to initialize mutex\n"); - exit(62); - } - - if (pthread_create(&thread->thread_id, NULL, marucam_worker_thread, (void*)thread) != 0) { - perror("failed to create a worker thread for webcam connection\n"); - exit(63); - } -} - -// MARUCAM_CMD_OPEN -void marucam_device_open(MaruCamState* state) -{ - struct v4l2_capability cap; - MaruCamParam *param = state->thread->param; - - param->top = 0; - v4l2_fd = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK); - if (v4l2_fd < 0) { - ERR("v4l2 device open failed.(/dev/video0)\n"); - param->errCode = EINVAL; - return; - } - if (xioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap) < 0) { - ERR("Could not qeury video capabilities\n"); - v4l2_close(v4l2_fd); - param->errCode = EINVAL; - return; - } - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || - !(cap.capabilities & V4L2_CAP_STREAMING)) { - ERR("Not supported video driver.\n"); - v4l2_close(v4l2_fd); - param->errCode = EINVAL; - return; - } - - memset(&dst_fmt, 0, sizeof(dst_fmt)); - INFO("Opened\n"); -} - -// MARUCAM_CMD_START_PREVIEW -void marucam_device_start_preview(MaruCamState* state) -{ - pthread_mutex_lock(&state->thread->mutex_lock); - state->streamon = 1; - state->buf_size = dst_fmt.fmt.pix.sizeimage; - if (pthread_cond_signal(&state->thread->thread_cond)) - ERR("failed to send a signal to the worker thread\n"); - pthread_mutex_unlock(&state->thread->mutex_lock); -} - -// MARUCAM_CMD_STOP_PREVIEW -void marucam_device_stop_preview(MaruCamState* state) -{ - pthread_mutex_lock(&state->thread->mutex_lock); - state->streamon = 0; - state->buf_size = 0; - pthread_mutex_unlock(&state->thread->mutex_lock); - sleep(0); -} - -void marucam_device_s_param(MaruCamState* state) -{ - struct v4l2_streamparm sp; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&sp, 0, sizeof(struct v4l2_streamparm)); - sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - sp.parm.capture.timeperframe.numerator = param->stack[0]; - sp.parm.capture.timeperframe.denominator = param->stack[1]; - - if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) { - ERR("failed to set FPS: %s\n", strerror(errno)); - param->errCode = errno; - } -} - -void marucam_device_g_param(MaruCamState* state) -{ - struct v4l2_streamparm sp; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&sp, 0, sizeof(struct v4l2_streamparm)); - sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (xioctl(v4l2_fd, VIDIOC_G_PARM, &sp) < 0) { - ERR("failed to get FPS: %s\n", strerror(errno)); - param->errCode = errno; - return; - } - param->stack[0] = sp.parm.capture.capability; - param->stack[1] = sp.parm.capture.timeperframe.numerator; - param->stack[2] = sp.parm.capture.timeperframe.denominator; -} - -void marucam_device_s_fmt(MaruCamState* state) -{ - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&dst_fmt, 0, sizeof(struct v4l2_format)); - dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_fmt.fmt.pix.width = param->stack[0]; - dst_fmt.fmt.pix.height = param->stack[1]; - dst_fmt.fmt.pix.pixelformat = param->stack[2]; - dst_fmt.fmt.pix.field = param->stack[3]; - - if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) { - ERR("failed to set video format: %s\n", strerror(errno)); - param->errCode = errno; - return; - } - - param->stack[0] = dst_fmt.fmt.pix.width; - param->stack[1] = dst_fmt.fmt.pix.height; - param->stack[2] = dst_fmt.fmt.pix.field; - param->stack[3] = dst_fmt.fmt.pix.pixelformat; - param->stack[4] = dst_fmt.fmt.pix.bytesperline; - param->stack[5] = dst_fmt.fmt.pix.sizeimage; - param->stack[6] = dst_fmt.fmt.pix.colorspace; - param->stack[7] = dst_fmt.fmt.pix.priv; -} - -void marucam_device_g_fmt(MaruCamState* state) -{ - struct v4l2_format format; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&format, 0, sizeof(struct v4l2_format)); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) { - ERR("failed to get video format: %s\n", strerror(errno)); - param->errCode = errno; - } else { - param->stack[0] = format.fmt.pix.width; - param->stack[1] = format.fmt.pix.height; - param->stack[2] = format.fmt.pix.field; - param->stack[3] = format.fmt.pix.pixelformat; - param->stack[4] = format.fmt.pix.bytesperline; - param->stack[5] = format.fmt.pix.sizeimage; - param->stack[6] = format.fmt.pix.colorspace; - param->stack[7] = format.fmt.pix.priv; - memcpy(&dst_fmt, &format, sizeof(format)); - } -} - -void marucam_device_try_fmt(MaruCamState* state) -{ - struct v4l2_format format; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&format, 0, sizeof(struct v4l2_format)); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - format.fmt.pix.width = param->stack[0]; - format.fmt.pix.height = param->stack[1]; - format.fmt.pix.pixelformat = param->stack[2]; - format.fmt.pix.field = param->stack[3]; - - if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) { - ERR("failed to check video format: %s\n", strerror(errno)); - param->errCode = errno; - return; - } - param->stack[0] = format.fmt.pix.width; - param->stack[1] = format.fmt.pix.height; - param->stack[2] = format.fmt.pix.field; - param->stack[3] = format.fmt.pix.pixelformat; - param->stack[4] = format.fmt.pix.bytesperline; - param->stack[5] = format.fmt.pix.sizeimage; - param->stack[6] = format.fmt.pix.colorspace; - param->stack[7] = format.fmt.pix.priv; -} - -void marucam_device_enum_fmt(MaruCamState* state) -{ - struct v4l2_fmtdesc format; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&format, 0, sizeof(struct v4l2_fmtdesc)); - format.index = param->stack[0]; - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) { - if (errno != EINVAL) - ERR("failed to enumerate video formats: %s\n", strerror(errno)); - param->errCode = errno; - return; - } - param->stack[0] = format.index; - param->stack[1] = format.flags; - param->stack[2] = format.pixelformat; - /* set description */ - memcpy(¶m->stack[3], format.description, sizeof(format.description)); -} - -void marucam_device_qctrl(MaruCamState* state) -{ - uint32_t i; - char name[32] = {0,}; - struct v4l2_queryctrl ctrl; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&ctrl, 0, sizeof(struct v4l2_queryctrl)); - ctrl.id = param->stack[0]; - - switch (ctrl.id) { - case V4L2_CID_BRIGHTNESS: - TRACE("Query : BRIGHTNESS\n"); - memcpy((void*)name, (void*)"brightness", 32); - i = 0; - break; - case V4L2_CID_CONTRAST: - TRACE("Query : CONTRAST\n"); - memcpy((void*)name, (void*)"contrast", 32); - i = 1; - break; - case V4L2_CID_SATURATION: - TRACE("Query : SATURATION\n"); - memcpy((void*)name, (void*)"saturation", 32); - i = 2; - break; - case V4L2_CID_SHARPNESS: - TRACE("Query : SHARPNESS\n"); - memcpy((void*)name, (void*)"sharpness", 32); - i = 3; - break; - default: - param->errCode = EINVAL; - return; - } - - if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) { - if (errno != EINVAL) - ERR("failed to query video controls : %s\n", strerror(errno)); - param->errCode = errno; - return; - } else { - struct v4l2_control sctrl; - memset(&sctrl, 0, sizeof(struct v4l2_control)); - sctrl.id = ctrl.id; - if ((ctrl.maximum + ctrl.minimum) == 0) { - sctrl.value = 0; - } else { - sctrl.value = (ctrl.maximum + ctrl.minimum) / 2; - } - if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) { - ERR("failed to set video control value : %s\n", strerror(errno)); - param->errCode = errno; - return; - } - qctrl_tbl[i].hit = 1; - qctrl_tbl[i].min = ctrl.minimum; - qctrl_tbl[i].max = ctrl.maximum; - qctrl_tbl[i].step = ctrl.step; - qctrl_tbl[i].init_val = ctrl.default_value; - } - - // set fixed values by FW configuration file - param->stack[0] = ctrl.id; - param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum - param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum - param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step - param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value - param->stack[5] = ctrl.flags; - /* name field setting */ - memcpy(¶m->stack[6], (void*)name, sizeof(ctrl.name)); -} - -void marucam_device_s_ctrl(MaruCamState* state) -{ - uint32_t i; - struct v4l2_control ctrl; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&ctrl, 0, sizeof(struct v4l2_control)); - ctrl.id = param->stack[0]; - - switch (ctrl.id) { - case V4L2_CID_BRIGHTNESS: - i = 0; - TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]); - break; - case V4L2_CID_CONTRAST: - i = 1; - TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]); - break; - case V4L2_CID_SATURATION: - i = 2; - TRACE("%d is set to the value of the SATURATION\n", param->stack[1]); - break; - case V4L2_CID_SHARPNESS: - i = 3; - TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]); - break; - default: - ERR("our emulator does not support this control : 0x%x\n", ctrl.id); - param->errCode = EINVAL; - return; - } - - ctrl.value = value_convert_from_guest(qctrl_tbl[i].min, - qctrl_tbl[i].max, param->stack[1]); - if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) { - ERR("failed to set video control value : value(%d), %s\n", param->stack[1], strerror(errno)); - param->errCode = errno; - return; - } -} - -void marucam_device_g_ctrl(MaruCamState* state) -{ - uint32_t i; - struct v4l2_control ctrl; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&ctrl, 0, sizeof(struct v4l2_control)); - ctrl.id = param->stack[0]; - - switch (ctrl.id) { - case V4L2_CID_BRIGHTNESS: - TRACE("Gets the value of the BRIGHTNESS\n"); - i = 0; - break; - case V4L2_CID_CONTRAST: - TRACE("Gets the value of the CONTRAST\n"); - i = 1; - break; - case V4L2_CID_SATURATION: - TRACE("Gets the value of the SATURATION\n"); - i = 2; - break; - case V4L2_CID_SHARPNESS: - TRACE("Gets the value of the SHARPNESS\n"); - i = 3; - break; - default: - ERR("our emulator does not support this control : 0x%x\n", ctrl.id); - param->errCode = EINVAL; - return; - } - - if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) { - ERR("failed to get video control value : %s\n", strerror(errno)); - param->errCode = errno; - return; - } - param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min, - qctrl_tbl[i].max, ctrl.value); - TRACE("Value : %d\n", param->stack[0]); -} - -void marucam_device_enum_fsizes(MaruCamState* state) -{ - struct v4l2_frmsizeenum fsize; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&fsize, 0, sizeof(struct v4l2_frmsizeenum)); - fsize.index = param->stack[0]; - fsize.pixel_format = param->stack[1]; - - if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) { - if (errno != EINVAL) - ERR("failed to get frame sizes : %s\n", strerror(errno)); - param->errCode = errno; - return; - } - - if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { - param->stack[0] = fsize.discrete.width; - param->stack[1] = fsize.discrete.height; - } else { - param->errCode = EINVAL; - ERR("Not Supported mode, we only support DISCRETE\n"); - } -} - -void marucam_device_enum_fintv(MaruCamState* state) -{ - struct v4l2_frmivalenum ival; - MaruCamParam *param = state->thread->param; - - param->top = 0; - memset(&ival, 0, sizeof(struct v4l2_frmivalenum)); - ival.index = param->stack[0]; - ival.pixel_format = param->stack[1]; - ival.width = param->stack[2]; - ival.height = param->stack[3]; - - if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) { - if (errno != EINVAL) - ERR("failed to get frame intervals : %s\n", strerror(errno)); - param->errCode = errno; - return; - } - - if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { - param->stack[0] = ival.discrete.numerator; - param->stack[1] = ival.discrete.denominator; - } else { - param->errCode = EINVAL; - ERR("Not Supported mode, we only support DISCRETE\n"); - } -} - -// MARUCAM_CMD_CLOSE -void marucam_device_close(MaruCamState* state) -{ - pthread_mutex_lock(&state->thread->mutex_lock); - state->streamon = 0; - pthread_mutex_unlock(&state->thread->mutex_lock); - - marucam_reset_controls(); - - v4l2_close(v4l2_fd); - v4l2_fd = 0; - INFO("Closed\n"); -} +/* + * Implementation of MARU Virtual Camera device by PCI bus on Linux. + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "qemu-common.h" +#include "qemu-common.h" +#include "maru_camera_common.h" +#include "pci.h" +#include "kvm.h" +#include "tizen/src/debug_ch.h" + +#include + +#include +#include + +MULTI_DEBUG_CHANNEL(tizen, camera_linux); + +static int v4l2_fd; +static int convert_trial; + +static struct v4l2_format dst_fmt; + +static int xioctl(int fd, int req, void *arg) +{ + int r; + + do { + r = v4l2_ioctl(fd, req, arg); + } while ( r < 0 && errno == EINTR); + + return r; +} + +#define MARUCAM_CTRL_VALUE_MAX 20 +#define MARUCAM_CTRL_VALUE_MIN 1 +#define MARUCAM_CTRL_VALUE_MID 10 +#define MARUCAM_CTRL_VALUE_STEP 1 + +struct marucam_qctrl { + uint32_t id; + uint32_t hit; + int32_t min; + int32_t max; + int32_t step; + int32_t init_val; +}; + +static struct marucam_qctrl qctrl_tbl[] = { + { V4L2_CID_BRIGHTNESS, 0, }, + { V4L2_CID_CONTRAST, 0, }, + { V4L2_CID_SATURATION,0, }, + { V4L2_CID_SHARPNESS, 0, }, +}; + +static void marucam_reset_controls(void) +{ + uint32_t i; + for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) { + if (qctrl_tbl[i].hit) { + struct v4l2_control ctrl = {0,}; + ctrl.id = qctrl_tbl[i].id; + ctrl.value = qctrl_tbl[i].init_val; + if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) { + ERR("failed to set video control value while reset values : %s\n", strerror(errno)); + } + } + } +} + +static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value) +{ + double rate = 0.0; + int32_t dist = 0, ret = 0; + + dist = max - min; + + if (dist < MARUCAM_CTRL_VALUE_MAX) { + rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; + ret = min + (int32_t)(value / rate); + } else { + rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; + ret = min + (int32_t)(rate * value); + } + return ret; +} + +static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value) +{ + double rate = 0.0; + int32_t dist = 0, ret = 0; + + dist = max - min; + + if (dist < MARUCAM_CTRL_VALUE_MAX) { + rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; + ret = (int32_t)((double)(value - min) * rate); + } else { + rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; + ret = (int32_t)((double)(value - min) / rate); + } + + return ret; +} + +static int __v4l2_grab(MaruCamState *state) +{ + fd_set fds; + static uint32_t index = 0; + struct timeval tv; + void *buf; + int ret; + + FD_ZERO(&fds); + FD_SET(v4l2_fd, &fds); + + tv.tv_sec = 2; + tv.tv_usec = 0; + + ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv); + if ( ret < 0) { + if (errno == EINTR) + return 0; + ERR("select : %s\n", strerror(errno)); + return -1; + } + if (!ret) { + WARN("Timed out\n"); + return 0; + } + + if (!v4l2_fd) { + WARN("file descriptor is closed or not opened \n"); + return -1; + } + + buf = state->vaddr + (state->buf_size * index); + ret = v4l2_read(v4l2_fd, buf, state->buf_size); + if ( ret < 0) { + switch (errno) { + case EINVAL: + case ENOMEM: + ERR("v4l2_read failed : %s\n", strerror(errno)); + return -1; + case EAGAIN: + case EIO: + case EINTR: + default: + if (convert_trial-- == -1) { + ERR("Try count for v4l2_read is exceeded\n"); + return -1; + } + return 0; + } + } + + index = !index; + + qemu_mutex_lock(&state->thread_mutex); + if (state->streamon) { + if (state->req_frame) { + qemu_irq_raise(state->dev.irq[2]); + state->req_frame = 0; + } + ret = 1; + } else { + ret = -1; + } + qemu_mutex_unlock(&state->thread_mutex); + + return ret; +} + +// Worker thread +static void *marucam_worker_thread(void *thread_param) +{ + MaruCamState *state = (MaruCamState*)thread_param; + +wait_worker_thread: + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 0; + convert_trial = 10; + qemu_cond_wait(&state->thread_cond, &state->thread_mutex); + qemu_mutex_unlock(&state->thread_mutex); + INFO("Streaming on ......\n"); + + while (1) + { + qemu_mutex_lock(&state->thread_mutex); + if (state->streamon) { + qemu_mutex_unlock(&state->thread_mutex); + if (__v4l2_grab(state) < 0) { + INFO("...... Streaming off\n"); + goto wait_worker_thread; + } + } else { + qemu_mutex_unlock(&state->thread_mutex); + goto wait_worker_thread; + } + } + qemu_thread_exit((void*)0); +} + +void marucam_device_init(MaruCamState* state) +{ + qemu_thread_create(&state->thread_id, marucam_worker_thread, (void*)state); +} + +// MARUCAM_CMD_OPEN +void marucam_device_open(MaruCamState* state) +{ + struct v4l2_capability cap; + MaruCamParam *param = state->param; + + param->top = 0; + v4l2_fd = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK); + if (v4l2_fd < 0) { + ERR("v4l2 device open failed.(/dev/video0)\n"); + param->errCode = EINVAL; + return; + } + if (xioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap) < 0) { + ERR("Could not qeury video capabilities\n"); + v4l2_close(v4l2_fd); + param->errCode = EINVAL; + return; + } + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || + !(cap.capabilities & V4L2_CAP_STREAMING)) { + ERR("Not supported video driver.\n"); + v4l2_close(v4l2_fd); + param->errCode = EINVAL; + return; + } + + memset(&dst_fmt, 0, sizeof(dst_fmt)); + INFO("Opened\n"); +} + +// MARUCAM_CMD_START_PREVIEW +void marucam_device_start_preview(MaruCamState* state) +{ + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 1; + state->buf_size = dst_fmt.fmt.pix.sizeimage; + qemu_cond_signal(&state->thread_cond); + qemu_mutex_unlock(&state->thread_mutex); +} + +// MARUCAM_CMD_STOP_PREVIEW +void marucam_device_stop_preview(MaruCamState* state) +{ + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 0; + state->buf_size = 0; + qemu_mutex_unlock(&state->thread_mutex); + sleep(0); +} + +void marucam_device_s_param(MaruCamState* state) +{ + struct v4l2_streamparm sp; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&sp, 0, sizeof(struct v4l2_streamparm)); + sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + sp.parm.capture.timeperframe.numerator = param->stack[0]; + sp.parm.capture.timeperframe.denominator = param->stack[1]; + + if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) { + ERR("failed to set FPS: %s\n", strerror(errno)); + param->errCode = errno; + } +} + +void marucam_device_g_param(MaruCamState* state) +{ + struct v4l2_streamparm sp; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&sp, 0, sizeof(struct v4l2_streamparm)); + sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (xioctl(v4l2_fd, VIDIOC_G_PARM, &sp) < 0) { + ERR("failed to get FPS: %s\n", strerror(errno)); + param->errCode = errno; + return; + } + param->stack[0] = sp.parm.capture.capability; + param->stack[1] = sp.parm.capture.timeperframe.numerator; + param->stack[2] = sp.parm.capture.timeperframe.denominator; +} + +void marucam_device_s_fmt(MaruCamState* state) +{ + MaruCamParam *param = state->param; + + param->top = 0; + memset(&dst_fmt, 0, sizeof(struct v4l2_format)); + dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_fmt.fmt.pix.width = param->stack[0]; + dst_fmt.fmt.pix.height = param->stack[1]; + dst_fmt.fmt.pix.pixelformat = param->stack[2]; + dst_fmt.fmt.pix.field = param->stack[3]; + + if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) { + ERR("failed to set video format: %s\n", strerror(errno)); + param->errCode = errno; + return; + } + + param->stack[0] = dst_fmt.fmt.pix.width; + param->stack[1] = dst_fmt.fmt.pix.height; + param->stack[2] = dst_fmt.fmt.pix.field; + param->stack[3] = dst_fmt.fmt.pix.pixelformat; + param->stack[4] = dst_fmt.fmt.pix.bytesperline; + param->stack[5] = dst_fmt.fmt.pix.sizeimage; + param->stack[6] = dst_fmt.fmt.pix.colorspace; + param->stack[7] = dst_fmt.fmt.pix.priv; +} + +void marucam_device_g_fmt(MaruCamState* state) +{ + struct v4l2_format format; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&format, 0, sizeof(struct v4l2_format)); + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) { + ERR("failed to get video format: %s\n", strerror(errno)); + param->errCode = errno; + } else { + param->stack[0] = format.fmt.pix.width; + param->stack[1] = format.fmt.pix.height; + param->stack[2] = format.fmt.pix.field; + param->stack[3] = format.fmt.pix.pixelformat; + param->stack[4] = format.fmt.pix.bytesperline; + param->stack[5] = format.fmt.pix.sizeimage; + param->stack[6] = format.fmt.pix.colorspace; + param->stack[7] = format.fmt.pix.priv; + memcpy(&dst_fmt, &format, sizeof(format)); + } +} + +void marucam_device_try_fmt(MaruCamState* state) +{ + struct v4l2_format format; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&format, 0, sizeof(struct v4l2_format)); + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + format.fmt.pix.width = param->stack[0]; + format.fmt.pix.height = param->stack[1]; + format.fmt.pix.pixelformat = param->stack[2]; + format.fmt.pix.field = param->stack[3]; + + if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) { + ERR("failed to check video format: %s\n", strerror(errno)); + param->errCode = errno; + return; + } + param->stack[0] = format.fmt.pix.width; + param->stack[1] = format.fmt.pix.height; + param->stack[2] = format.fmt.pix.field; + param->stack[3] = format.fmt.pix.pixelformat; + param->stack[4] = format.fmt.pix.bytesperline; + param->stack[5] = format.fmt.pix.sizeimage; + param->stack[6] = format.fmt.pix.colorspace; + param->stack[7] = format.fmt.pix.priv; +} + +void marucam_device_enum_fmt(MaruCamState* state) +{ + struct v4l2_fmtdesc format; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&format, 0, sizeof(struct v4l2_fmtdesc)); + format.index = param->stack[0]; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) { + if (errno != EINVAL) + ERR("failed to enumerate video formats: %s\n", strerror(errno)); + param->errCode = errno; + return; + } + param->stack[0] = format.index; + param->stack[1] = format.flags; + param->stack[2] = format.pixelformat; + /* set description */ + memcpy(¶m->stack[3], format.description, sizeof(format.description)); +} + +void marucam_device_qctrl(MaruCamState* state) +{ + uint32_t i; + char name[32] = {0,}; + struct v4l2_queryctrl ctrl; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&ctrl, 0, sizeof(struct v4l2_queryctrl)); + ctrl.id = param->stack[0]; + + switch (ctrl.id) { + case V4L2_CID_BRIGHTNESS: + TRACE("Query : BRIGHTNESS\n"); + memcpy((void*)name, (void*)"brightness", 32); + i = 0; + break; + case V4L2_CID_CONTRAST: + TRACE("Query : CONTRAST\n"); + memcpy((void*)name, (void*)"contrast", 32); + i = 1; + break; + case V4L2_CID_SATURATION: + TRACE("Query : SATURATION\n"); + memcpy((void*)name, (void*)"saturation", 32); + i = 2; + break; + case V4L2_CID_SHARPNESS: + TRACE("Query : SHARPNESS\n"); + memcpy((void*)name, (void*)"sharpness", 32); + i = 3; + break; + default: + param->errCode = EINVAL; + return; + } + + if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) { + if (errno != EINVAL) + ERR("failed to query video controls : %s\n", strerror(errno)); + param->errCode = errno; + return; + } else { + struct v4l2_control sctrl; + memset(&sctrl, 0, sizeof(struct v4l2_control)); + sctrl.id = ctrl.id; + if ((ctrl.maximum + ctrl.minimum) == 0) { + sctrl.value = 0; + } else { + sctrl.value = (ctrl.maximum + ctrl.minimum) / 2; + } + if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) { + ERR("failed to set video control value : %s\n", strerror(errno)); + param->errCode = errno; + return; + } + qctrl_tbl[i].hit = 1; + qctrl_tbl[i].min = ctrl.minimum; + qctrl_tbl[i].max = ctrl.maximum; + qctrl_tbl[i].step = ctrl.step; + qctrl_tbl[i].init_val = ctrl.default_value; + } + + // set fixed values by FW configuration file + param->stack[0] = ctrl.id; + param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum + param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum + param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step + param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value + param->stack[5] = ctrl.flags; + /* name field setting */ + memcpy(¶m->stack[6], (void*)name, sizeof(ctrl.name)); +} + +void marucam_device_s_ctrl(MaruCamState* state) +{ + uint32_t i; + struct v4l2_control ctrl; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&ctrl, 0, sizeof(struct v4l2_control)); + ctrl.id = param->stack[0]; + + switch (ctrl.id) { + case V4L2_CID_BRIGHTNESS: + i = 0; + TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]); + break; + case V4L2_CID_CONTRAST: + i = 1; + TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]); + break; + case V4L2_CID_SATURATION: + i = 2; + TRACE("%d is set to the value of the SATURATION\n", param->stack[1]); + break; + case V4L2_CID_SHARPNESS: + i = 3; + TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]); + break; + default: + ERR("our emulator does not support this control : 0x%x\n", ctrl.id); + param->errCode = EINVAL; + return; + } + + ctrl.value = value_convert_from_guest(qctrl_tbl[i].min, + qctrl_tbl[i].max, param->stack[1]); + if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) { + ERR("failed to set video control value : value(%d), %s\n", param->stack[1], strerror(errno)); + param->errCode = errno; + return; + } +} + +void marucam_device_g_ctrl(MaruCamState* state) +{ + uint32_t i; + struct v4l2_control ctrl; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&ctrl, 0, sizeof(struct v4l2_control)); + ctrl.id = param->stack[0]; + + switch (ctrl.id) { + case V4L2_CID_BRIGHTNESS: + TRACE("Gets the value of the BRIGHTNESS\n"); + i = 0; + break; + case V4L2_CID_CONTRAST: + TRACE("Gets the value of the CONTRAST\n"); + i = 1; + break; + case V4L2_CID_SATURATION: + TRACE("Gets the value of the SATURATION\n"); + i = 2; + break; + case V4L2_CID_SHARPNESS: + TRACE("Gets the value of the SHARPNESS\n"); + i = 3; + break; + default: + ERR("our emulator does not support this control : 0x%x\n", ctrl.id); + param->errCode = EINVAL; + return; + } + + if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) { + ERR("failed to get video control value : %s\n", strerror(errno)); + param->errCode = errno; + return; + } + param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min, + qctrl_tbl[i].max, ctrl.value); + TRACE("Value : %d\n", param->stack[0]); +} + +void marucam_device_enum_fsizes(MaruCamState* state) +{ + struct v4l2_frmsizeenum fsize; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&fsize, 0, sizeof(struct v4l2_frmsizeenum)); + fsize.index = param->stack[0]; + fsize.pixel_format = param->stack[1]; + + if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) { + if (errno != EINVAL) + ERR("failed to get frame sizes : %s\n", strerror(errno)); + param->errCode = errno; + return; + } + + if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + param->stack[0] = fsize.discrete.width; + param->stack[1] = fsize.discrete.height; + } else { + param->errCode = EINVAL; + ERR("Not Supported mode, we only support DISCRETE\n"); + } +} + +void marucam_device_enum_fintv(MaruCamState* state) +{ + struct v4l2_frmivalenum ival; + MaruCamParam *param = state->param; + + param->top = 0; + memset(&ival, 0, sizeof(struct v4l2_frmivalenum)); + ival.index = param->stack[0]; + ival.pixel_format = param->stack[1]; + ival.width = param->stack[2]; + ival.height = param->stack[3]; + + if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) { + if (errno != EINVAL) + ERR("failed to get frame intervals : %s\n", strerror(errno)); + param->errCode = errno; + return; + } + + if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { + param->stack[0] = ival.discrete.numerator; + param->stack[1] = ival.discrete.denominator; + } else { + param->errCode = EINVAL; + ERR("Not Supported mode, we only support DISCRETE\n"); + } +} + +// MARUCAM_CMD_CLOSE +void marucam_device_close(MaruCamState* state) +{ + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 0; + qemu_mutex_unlock(&state->thread_mutex); + + marucam_reset_controls(); + + v4l2_close(v4l2_fd); + v4l2_fd = 0; + INFO("Closed\n"); +} diff --git a/tizen/src/hw/maru_camera_win32_interface.h b/tizen/src/hw/maru_camera_win32_interface.h new file mode 100644 index 0000000000..d68cb85746 --- /dev/null +++ b/tizen/src/hw/maru_camera_win32_interface.h @@ -0,0 +1,932 @@ +/* + * Interface definition header for Windows host. + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef _MARU_CAMERA_INTERFACE_H_ +#define _MARU_CAMERA_INTERFACE_H_ + +static const WCHAR HWCPinName[] = L"HWCInputPin\0"; +static const WCHAR HWCFilterName[] = L"HWCFilter\0"; + +/* Forward Declarations */ +FWD_DECL(IBaseFilter); +FWD_DECL(IFilterGraph); + +/* defines */ +#define MAX_PIN_NAME 128 +#define MAX_FILTER_NAME 128 + +typedef LONGLONG REFERENCE_TIME; +typedef long OAFilterState; +typedef DWORD_PTR HSEMAPHORE; +typedef DWORD_PTR HEVENT; + +typedef enum _FilterState { + State_Stopped, + State_Paused, + State_Running +} FILTER_STATE; + +typedef struct _FilterInfo { + WCHAR achName[MAX_FILTER_NAME]; + IFilterGraph *pGraph; +} FILTER_INFO; + +typedef enum _PinDirection +{ PINDIR_INPUT = 0, + PINDIR_OUTPUT = ( PINDIR_INPUT + 1 ) +} PIN_DIRECTION; + +typedef struct _PinInfo { + IBaseFilter *pFilter; + PIN_DIRECTION dir; + WCHAR achName[MAX_PIN_NAME]; +} PIN_INFO; + +typedef struct _AllocatorProperties { + long cBuffers; + long cbBuffer; + long cbAlign; + long cbPrefix; +} ALLOCATOR_PROPERTIES; + +typedef struct _AMMediaType { + GUID majortype; + GUID subtype; + BOOL bFixedSizeSamples; + BOOL bTemporalCompression; + ULONG lSampleSize; + GUID formattype; + IUnknown *pUnk; + ULONG cbFormat; + BYTE *pbFormat; +} AM_MEDIA_TYPE; + +typedef enum tagVideoProcAmpFlags { + VideoProcAmp_Flags_Auto = 0x0001, + VideoProcAmp_Flags_Manual = 0x0002 +} VideoProcAmpFlags; + +typedef enum tagVideoProcAmpProperty { + VideoProcAmp_Brightness, + VideoProcAmp_Contrast, + VideoProcAmp_Hue, + VideoProcAmp_Saturation, + VideoProcAmp_Sharpness, + VideoProcAmp_Gamma, + VideoProcAmp_ColorEnable, + VideoProcAmp_WhiteBalance, + VideoProcAmp_BacklightCompensation, + VideoProcAmp_Gain +} VideoProcAmpProperty; + +typedef struct tagVIDEOINFOHEADER { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + BITMAPINFOHEADER bmiHeader; +} VIDEOINFOHEADER; + +typedef struct _VIDEO_STREAM_CONFIG_CAPS +{ + GUID guid; + ULONG VideoStandard; + SIZE InputSize; + SIZE MinCroppingSize; + SIZE MaxCroppingSize; + int CropGranularityX; + int CropGranularityY; + int CropAlignX; + int CropAlignY; + SIZE MinOutputSize; + SIZE MaxOutputSize; + int OutputGranularityX; + int OutputGranularityY; + int StretchTapsX; + int StretchTapsY; + int ShrinkTapsX; + int ShrinkTapsY; + LONGLONG MinFrameInterval; + LONGLONG MaxFrameInterval; + LONG MinBitsPerSecond; + LONG MaxBitsPerSecond; +} VIDEO_STREAM_CONFIG_CAPS; + + +/* Interface & Class GUIDs */ +static const IID IID_IGrabCallback = {0x4C337035,0xC89E,0x4B42,{0x9B,0x0C,0x36,0x74,0x44,0xDD,0x70,0xDD}}; + +EXTERN_C const IID IID_IBaseFilter; +EXTERN_C const IID IID_ICreateDevEnum; +EXTERN_C const IID IID_IGraphBuilder; +EXTERN_C const IID IID_IMediaSeeking; +EXTERN_C const IID IID_IMediaEventSink; +EXTERN_C const IID IID_IMemInputPin; +EXTERN_C const IID IID_IEnumPins; +EXTERN_C const IID IID_IMediaFilter; +EXTERN_C const IID IID_IEnumMediaTypes; +EXTERN_C const IID IID_IMemAllocator; +EXTERN_C const IID IID_IPin; +EXTERN_C const IID IID_ICaptureGraphBuilder2; +EXTERN_C const IID IID_IFileSinkFilter; +EXTERN_C const IID IID_IAMCopyCaptureFileProgress; +EXTERN_C const IID IID_IEnumFilters; +EXTERN_C const IID IID_IMediaSample; +EXTERN_C const IID IID_IMediaControl; +EXTERN_C const IID IID_IAMStreamConfig; +EXTERN_C const IID IID_IAMVideoProcAmp; + +EXTERN_C const IID CLSID_CaptureGraphBuilder2; +EXTERN_C const IID CLSID_VideoInputDeviceCategory; +EXTERN_C const IID CLSID_AudioRender; +EXTERN_C const IID CLSID_SystemDeviceEnum; +EXTERN_C const IID CLSID_AudioRendererCategory; +EXTERN_C const IID CLSID_FilterGraph; +EXTERN_C const IID CLSID_InfTee; +EXTERN_C const IID CLSID_VideoMixingRenderer9; +EXTERN_C const IID CLSID_MemoryAllocator; + + +/* other types GUIDs*/ +EXTERN_C const IID MEDIATYPE_Audio; +EXTERN_C const IID MEDIATYPE_Video; +EXTERN_C const IID MEDIATYPE_Stream; +EXTERN_C const IID MEDIASUBTYPE_PCM; +EXTERN_C const IID MEDIASUBTYPE_WAVE; +EXTERN_C const IID MEDIASUBTYPE_Avi; +EXTERN_C const IID MEDIASUBTYPE_RGB32; +EXTERN_C const IID MEDIASUBTYPE_YV12; +EXTERN_C const IID MEDIASUBTYPE_YUY2; +EXTERN_C const IID MEDIASUBTYPE_I420; +EXTERN_C const IID MEDIASUBTYPE_YUYV; +EXTERN_C const IID FORMAT_WaveFormatEx; +EXTERN_C const IID FORMAT_VideoInfo; +EXTERN_C const IID FORMAT_VideoInfo2; +EXTERN_C const IID PIN_CATEGORY_CAPTURE; +EXTERN_C const IID PIN_CATEGORY_PREVIEW; + + +#define MEDIATYPE_NULL GUID_NULL +#define MEDIASUBTYPE_NULL GUID_NULL + +#define INTERFACE IGrabCallback +DECLARE_INTERFACE_(IGrabCallback, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Grab)(THIS_ ULONG,BYTE*) PURE; +}; +#undef INTERFACE + +#ifdef COBJMACROS +#define IGrabCallback_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b) +#define IGrabCallback_AddRef(T) (T)->lpVtbl->AddRef(T) +#define IGrabCallback_Release(T) (T)->lpVtbl->Release(T) +#define IGrabCallback_Grab(T,a,b) (T)->lpVtbl->Grab(T,a,b) +#endif /* COBJMACROS */ + +#define INTERFACE IAMCopyCaptureFileProgress +DECLARE_INTERFACE_(IAMCopyCaptureFileProgress, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Progress)(THIS_ int) PURE; +}; +#undef INTERFACE +#define INTERFACE IReferenceClock +DECLARE_INTERFACE_(IReferenceClock, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *) PURE; + STDMETHOD(AdviseTime)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HEVENT, DWORD_PTR *) PURE; + STDMETHOD(AdvisePeriodic)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HSEMAPHORE, DWORD_PTR *) PURE; + STDMETHOD(Unadvise)(THIS_ DWORD_PTR) PURE; +}; +#undef INTERFACE +#define INTERFACE IEnumFilters +DECLARE_INTERFACE_(IEnumFilters, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Next)(THIS_ ULONG, IBaseFilter **, ULONG *) PURE; + STDMETHOD(Skip)(THIS_ ULONG) PURE; + STDMETHOD(Reset)(THIS) PURE; + STDMETHOD(Clone)(THIS_ IEnumFilters **) PURE; +}; +#undef INTERFACE +#define INTERFACE IEnumMediaTypes +DECLARE_INTERFACE_(IEnumMediaTypes, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Next)(THIS_ ULONG, AM_MEDIA_TYPE **, ULONG *) PURE; + STDMETHOD(Skip)(THIS_ ULONG) PURE; + STDMETHOD(Reset)(THIS) PURE; + STDMETHOD(Clone)(THIS_ IEnumMediaTypes **) PURE; +}; +#undef INTERFACE +#define INTERFACE IPin +DECLARE_INTERFACE_(IPin, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(ReceiveConnection)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(Disconnect)(THIS) PURE; + STDMETHOD(ConnectedTo)(THIS_ IPin **) PURE; + STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE *) PURE; + STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO *) PURE; + STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION *) PURE; + STDMETHOD(QueryId)(THIS_ LPWSTR *) PURE; + STDMETHOD(QueryAccept)(THIS_ const AM_MEDIA_TYPE *) PURE; + STDMETHOD(EnumMediaTypes)(THIS_ IEnumMediaTypes **) PURE; + STDMETHOD(QueryInternalConnections)(THIS_ IPin **, ULONG *) PURE; + STDMETHOD(EndOfStream)(THIS) PURE; + STDMETHOD(BeginFlush)(THIS) PURE; + STDMETHOD(EndFlush)(THIS) PURE; + STDMETHOD(NewSegment)(THIS_ REFERENCE_TIME, REFERENCE_TIME, double) PURE; +}; +#undef INTERFACE +#define INTERFACE IEnumPins +DECLARE_INTERFACE_(IEnumPins, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Next)(THIS_ ULONG, IPin **, ULONG *) PURE; + STDMETHOD(Skip)(THIS_ ULONG) PURE; + STDMETHOD(Reset)(THIS) PURE; + STDMETHOD(Clone)(THIS_ IEnumPins **) PURE; +}; +#undef INTERFACE +#define INTERFACE IMediaFilter +DECLARE_INTERFACE_(IMediaFilter, IPersist) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetClassID)(THIS_ CLSID*) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE; + STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE; + STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE; + STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE; +}; +#undef INTERFACE +#define INTERFACE IBaseFilter +//DECLARE_INTERFACE_(IBaseFilter, IMediaFilter) +_COM_interface IBaseFilter { CONST_VTABLE struct IBaseFilterVtbl *lpVtbl; }; +typedef CONST_VTABLE struct IBaseFilterVtbl IBaseFilterVtbl; +CONST_VTABLE struct IBaseFilterVtbl +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetClassID)(THIS_ CLSID*) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE; + STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE; + STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE; + STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE; + STDMETHOD(EnumPins)(THIS_ IEnumPins **) PURE; + STDMETHOD(FindPin)(THIS_ LPCWSTR, IPin **) PURE; + STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO *) PURE; + STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph *, LPCWSTR) PURE; + STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR *) PURE; +}; +#undef INTERFACE +#define INTERFACE IFilterGraph +//DECLARE_INTERFACE_(IFilterGraph ,IUnknown) +_COM_interface IFilterGraph { CONST_VTABLE struct IFilterGraphVtbl *lpVtbl; }; +typedef CONST_VTABLE struct IFilterGraphVtbl IFilterGraphVtbl; +CONST_VTABLE struct IFilterGraphVtbl +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE; + STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE; + STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE; + STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE; + STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(Reconnect)(THIS_ IPin *) PURE; + STDMETHOD(Disconnect)(THIS_ IPin *) PURE; + STDMETHOD(SetDefaultSyncSource)(THIS) PURE; +}; +#undef INTERFACE +#define INTERFACE IGraphBuilder +DECLARE_INTERFACE_(IGraphBuilder ,IFilterGraph) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE; + STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE; + STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE; + STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE; + STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE; + STDMETHOD(Reconnect)(THIS_ IPin *) PURE; + STDMETHOD(Disconnect)(THIS_ IPin *) PURE; + STDMETHOD(SetDefaultSyncSource)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin *, IPin *) PURE; + STDMETHOD(Render)(THIS_ IPin *) PURE; + STDMETHOD(RenderFile)(THIS_ LPCWSTR, LPCWSTR) PURE; + STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR, LPCWSTR, IBaseFilter **) PURE; + STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE; + STDMETHOD(Abort)(THIS) PURE; + STDMETHOD(ShouldOperationContinue)(THIS) PURE; +}; +#undef INTERFACE +#define INTERFACE ICreateDevEnum +DECLARE_INTERFACE_(ICreateDevEnum, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(CreateClassEnumerator)(THIS_ REFCLSID, IEnumMoniker **, DWORD) PURE; +}; +#undef INTERFACE +#define INTERFACE IMediaSample +DECLARE_INTERFACE_(IMediaSample, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetPointer)(THIS_ BYTE **) PURE; + STDMETHOD_(long, GetSize)(THIS) PURE; + STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE; + STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE; + STDMETHOD(IsSyncPoint)(THIS) PURE; + STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE; + STDMETHOD(IsPreroll)(THIS) PURE; + STDMETHOD(SetPreroll)(THIS_ BOOL) PURE; + STDMETHOD_(long, GetActualDataLength)(THIS) PURE; + STDMETHOD(SetActualDataLength)(THIS_ long) PURE; + STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE; + STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE; + STDMETHOD(IsDiscontinuity)(THIS) PURE; + STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE; + STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE; + STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE; +}; +#undef INTERFACE +#define INTERFACE IMemAllocator +DECLARE_INTERFACE_(IMemAllocator, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES *, ALLOCATOR_PROPERTIES *) PURE; + STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES *) PURE; + STDMETHOD(Commit)(THIS) PURE; + STDMETHOD(Decommit)(THIS) PURE; + STDMETHOD(GetBuffer)(THIS_ IMediaSample **, REFERENCE_TIME *, REFERENCE_TIME *, DWORD) PURE; + STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample *) PURE; + +}; +#undef INTERFACE +#define INTERFACE IMemInputPin +DECLARE_INTERFACE_(IMemInputPin, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetAllocator)(THIS_ IMemAllocator **) PURE; + STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator *, BOOL) PURE; + STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES *) PURE; + STDMETHOD(Receive)(THIS_ IMediaSample *) PURE; + STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample **, long, long *) PURE; + STDMETHOD(ReceiveCanBlock)(THIS) PURE; +}; +#undef INTERFACE +#define INTERFACE IFileSinkFilter +DECLARE_INTERFACE_(IFileSinkFilter, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetFileName)(THIS_ LPCOLESTR,const AM_MEDIA_TYPE *) PURE; + STDMETHOD(GetCurFile)(THIS_ LPOLESTR *,AM_MEDIA_TYPE*) PURE; +}; +#undef INTERFACE +#define INTERFACE ICaptureGraphBuilder2 +DECLARE_INTERFACE_(ICaptureGraphBuilder2, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetFiltergraph)(THIS_ IGraphBuilder*) PURE; + STDMETHOD(GetFiltergraph)(THIS_ IGraphBuilder**) PURE; + STDMETHOD(SetOutputFileName)(THIS_ const GUID*,LPCOLESTR,IBaseFilter**,IFileSinkFilter**) PURE; + STDMETHOD(FindInterface)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFIID,void**) PURE; + STDMETHOD(RenderStream)(THIS_ const GUID*,const GUID*,IUnknown*,IBaseFilter*,IBaseFilter*) PURE; + STDMETHOD(ControlStream)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFERENCE_TIME*,REFERENCE_TIME*,WORD,WORD) PURE; + STDMETHOD(AllocCapFile)(THIS_ LPCOLESTR,DWORDLONG) PURE; + STDMETHOD(CopyCaptureFile)(THIS_ LPOLESTR,LPOLESTR,int,IAMCopyCaptureFileProgress*) PURE; + STDMETHOD(FindPin)(THIS_ IUnknown*,PIN_DIRECTION,const GUID*,const GUID*,BOOL,int,IPin**) PURE; +}; +#undef INTERFACE +#define INTERFACE IAMStreamConfig +DECLARE_INTERFACE_(IAMStreamConfig, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE; + STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE; + STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE; +}; +#undef INTERFACE +#define INTERFACE IAMVideoProcAmp +DECLARE_INTERFACE_(IAMVideoProcAmp, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetRange)(THIS_ long,long*,long*,long*,long*,long*) PURE; + STDMETHOD(Set)(THIS_ long,long,long) PURE; + STDMETHOD(Get)(THIS_ long,long*,long*) PURE; +}; +#undef INTERFACE +#define INTERFACE IMediaControl +DECLARE_INTERFACE_(IMediaControl, IDispatch) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetTypeInfoCount)(THIS_ UINT*); + STDMETHOD(GetTypeInfo)(THIS_ UINT,LCID,ITypeInfo**); + STDMETHOD(GetIDsOfNames)(THIS_ REFIID,LPOLESTR*,UINT,LCID,DISPID*); + STDMETHOD(Invoke)(THIS_ DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); + STDMETHOD(Run)(THIS); + STDMETHOD(Pause)(THIS); + STDMETHOD(Stop)(THIS); + STDMETHOD(GetState)(THIS_ LONG, OAFilterState*); + STDMETHOD(RenderFile)(THIS_ BSTR); + STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**); + STDMETHOD(get_FilterCollection)(THIS_ IDispatch**); + STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**); + STDMETHOD(StopWhenReady)(THIS); +}; +#undef INTERFACE + +#ifdef COBJMACROS +#define ICreateDevEnum_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define ICreateDevEnum_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define ICreateDevEnum_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define ICreateDevEnum_CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags) \ + ( (This)->lpVtbl -> CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IPin_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IPin_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IPin_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IPin_Connect(This,pReceivePin,pmt) \ + ( (This)->lpVtbl -> Connect(This,pReceivePin,pmt) ) +#define IPin_ReceiveConnection(This,pConnector,pmt) \ + ( (This)->lpVtbl -> ReceiveConnection(This,pConnector,pmt) ) +#define IPin_Disconnect(This) \ + ( (This)->lpVtbl -> Disconnect(This) ) +#define IPin_ConnectedTo(This,pPin) \ + ( (This)->lpVtbl -> ConnectedTo(This,pPin) ) +#define IPin_ConnectionMediaType(This,pmt) \ + ( (This)->lpVtbl -> ConnectionMediaType(This,pmt) ) +#define IPin_QueryPinInfo(This,pInfo) \ + ( (This)->lpVtbl -> QueryPinInfo(This,pInfo) ) +#define IPin_QueryDirection(This,pPinDir) \ + ( (This)->lpVtbl -> QueryDirection(This,pPinDir) ) +#define IPin_QueryId(This,Id) \ + ( (This)->lpVtbl -> QueryId(This,Id) ) +#define IPin_QueryAccept(This,pmt) \ + ( (This)->lpVtbl -> QueryAccept(This,pmt) ) +#define IPin_EnumMediaTypes(This,ppEnum) \ + ( (This)->lpVtbl -> EnumMediaTypes(This,ppEnum) ) +#define IPin_QueryInternalConnections(This,apPin,nPin) \ + ( (This)->lpVtbl -> QueryInternalConnections(This,apPin,nPin) ) +#define IPin_EndOfStream(This) \ + ( (This)->lpVtbl -> EndOfStream(This) ) +#define IPin_BeginFlush(This) \ + ( (This)->lpVtbl -> BeginFlush(This) ) +#define IPin_EndFlush(This) \ + ( (This)->lpVtbl -> EndFlush(This) ) +#define IPin_NewSegment(This,tStart,tStop,dRate) \ + ( (This)->lpVtbl -> NewSegment(This,tStart,tStop,dRate) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IEnumPins_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IEnumPins_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IEnumPins_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IEnumPins_Next(This,cPins,ppPins,pcFetched) \ + ( (This)->lpVtbl -> Next(This,cPins,ppPins,pcFetched) ) +#define IEnumPins_Skip(This,cPins) \ + ( (This)->lpVtbl -> Skip(This,cPins) ) +#define IEnumPins_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) +#define IEnumPins_Clone(This,ppEnum) \ + ( (This)->lpVtbl -> Clone(This,ppEnum) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IAMStreamConfig_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IAMStreamConfig_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IAMStreamConfig_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IAMStreamConfig_SetFormat(This,pmt) \ + ( (This)->lpVtbl -> SetFormat(This,pmt) ) +#define IAMStreamConfig_GetFormat(This,ppmt) \ + ( (This)->lpVtbl -> GetFormat(This,ppmt) ) +#define IAMStreamConfig_GetNumberOfCapabilities(This,piCount,piSize) \ + ( (This)->lpVtbl -> GetNumberOfCapabilities(This,piCount,piSize) ) +#define IAMStreamConfig_GetStreamCaps(This,iIndex,ppmt,pSCC) \ + ( (This)->lpVtbl -> GetStreamCaps(This,iIndex,ppmt,pSCC) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IFilterGraph_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IFilterGraph_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IFilterGraph_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IFilterGraph_AddFilter(This,pFilter,pName) \ + ( (This)->lpVtbl -> AddFilter(This,pFilter,pName) ) +#define IFilterGraph_RemoveFilter(This,pFilter) \ + ( (This)->lpVtbl -> RemoveFilter(This,pFilter) ) +#define IFilterGraph_EnumFilters(This,ppEnum) \ + ( (This)->lpVtbl -> EnumFilters(This,ppEnum) ) +#define IFilterGraph_FindFilterByName(This,pName,ppFilter) \ + ( (This)->lpVtbl -> FindFilterByName(This,pName,ppFilter) ) +#define IFilterGraph_ConnectDirect(This,ppinOut,ppinIn,pmt) \ + ( (This)->lpVtbl -> ConnectDirect(This,ppinOut,ppinIn,pmt) ) +#define IFilterGraph_Reconnect(This,ppin) \ + ( (This)->lpVtbl -> Reconnect(This,ppin) ) +#define IFilterGraph_Disconnect(This,ppin) \ + ( (This)->lpVtbl -> Disconnect(This,ppin) ) +#define IFilterGraph_SetDefaultSyncSource(This) \ + ( (This)->lpVtbl -> SetDefaultSyncSource(This) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IMediaFilter_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IMediaFilter_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IMediaFilter_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IMediaFilter_GetClassID(This,pClassID) \ + ( (This)->lpVtbl -> GetClassID(This,pClassID) ) +#define IMediaFilter_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) +#define IMediaFilter_Pause(This) \ + ( (This)->lpVtbl -> Pause(This) ) +#define IMediaFilter_Run(This,tStart) \ + ( (This)->lpVtbl -> Run(This,tStart) ) +#define IMediaFilter_GetState(This,dwMilliSecsTimeout,State) \ + ( (This)->lpVtbl -> GetState(This,dwMilliSecsTimeout,State) ) +#define IMediaFilter_SetSyncSource(This,pClock) \ + ( (This)->lpVtbl -> SetSyncSource(This,pClock) ) +#define IMediaFilter_GetSyncSource(This,pClock) \ + ( (This)->lpVtbl -> GetSyncSource(This,pClock) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IBaseFilter_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IBaseFilter_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IBaseFilter_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IBaseFilter_GetClassID(This,pClassID) \ + ( (This)->lpVtbl -> GetClassID(This,pClassID) ) +#define IBaseFilter_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) +#define IBaseFilter_Pause(This) \ + ( (This)->lpVtbl -> Pause(This) ) +#define IBaseFilter_Run(This,tStart) \ + ( (This)->lpVtbl -> Run(This,tStart) ) +#define IBaseFilter_GetState(This,dwMilliSecsTimeout,State) \ + ( (This)->lpVtbl -> GetState(This,dwMilliSecsTimeout,State) ) +#define IBaseFilter_SetSyncSource(This,pClock) \ + ( (This)->lpVtbl -> SetSyncSource(This,pClock) ) +#define IBaseFilter_GetSyncSource(This,pClock) \ + ( (This)->lpVtbl -> GetSyncSource(This,pClock) ) +#define IBaseFilter_EnumPins(This,ppEnum) \ + ( (This)->lpVtbl -> EnumPins(This,ppEnum) ) +#define IBaseFilter_FindPin(This,Id,ppPin) \ + ( (This)->lpVtbl -> FindPin(This,Id,ppPin) ) +#define IBaseFilter_QueryFilterInfo(This,pInfo) \ + ( (This)->lpVtbl -> QueryFilterInfo(This,pInfo) ) +#define IBaseFilter_JoinFilterGraph(This,pGraph,pName) \ + ( (This)->lpVtbl -> JoinFilterGraph(This,pGraph,pName) ) +#define IBaseFilter_QueryVendorInfo(This,pVendorInfo) \ + ( (This)->lpVtbl -> QueryVendorInfo(This,pVendorInfo) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IMediaSample_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IMediaSample_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IMediaSample_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IMediaSample_GetPointer(This,ppBuffer) \ + ( (This)->lpVtbl -> GetPointer(This,ppBuffer) ) +#define IMediaSample_GetSize(This) \ + ( (This)->lpVtbl -> GetSize(This) ) +#define IMediaSample_GetTime(This,pTimeStart,pTimeEnd) \ + ( (This)->lpVtbl -> GetTime(This,pTimeStart,pTimeEnd) ) +#define IMediaSample_SetTime(This,pTimeStart,pTimeEnd) \ + ( (This)->lpVtbl -> SetTime(This,pTimeStart,pTimeEnd) ) +#define IMediaSample_IsSyncPoint(This) \ + ( (This)->lpVtbl -> IsSyncPoint(This) ) +#define IMediaSample_SetSyncPoint(This,bIsSyncPoint) \ + ( (This)->lpVtbl -> SetSyncPoint(This,bIsSyncPoint) ) +#define IMediaSample_IsPreroll(This) \ + ( (This)->lpVtbl -> IsPreroll(This) ) +#define IMediaSample_SetPreroll(This,bIsPreroll) \ + ( (This)->lpVtbl -> SetPreroll(This,bIsPreroll) ) +#define IMediaSample_GetActualDataLength(This) \ + ( (This)->lpVtbl -> GetActualDataLength(This) ) +#define IMediaSample_SetActualDataLength(This,length) \ + ( (This)->lpVtbl -> SetActualDataLength(This,length) ) +#define IMediaSample_GetMediaType(This,ppMediaType) \ + ( (This)->lpVtbl -> GetMediaType(This,ppMediaType) ) +#define IMediaSample_SetMediaType(This,pMediaType) \ + ( (This)->lpVtbl -> SetMediaType(This,pMediaType) ) +#define IMediaSample_IsDiscontinuity(This) \ + ( (This)->lpVtbl -> IsDiscontinuity(This) ) +#define IMediaSample_SetDiscontinuity(This,bDiscontinuity) \ + ( (This)->lpVtbl -> SetDiscontinuity(This,bDiscontinuity) ) +#define IMediaSample_GetMediaTime(This,pTimeStart,pTimeEnd) \ + ( (This)->lpVtbl -> GetMediaTime(This,pTimeStart,pTimeEnd) ) +#define IMediaSample_SetMediaTime(This,pTimeStart,pTimeEnd) \ + ( (This)->lpVtbl -> SetMediaTime(This,pTimeStart,pTimeEnd) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IEnumFilters_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IEnumFilters_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IEnumFilters_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IEnumFilters_Next(This,cFilters,ppFilter,pcFetched) \ + ( (This)->lpVtbl -> Next(This,cFilters,ppFilter,pcFetched) ) +#define IEnumFilters_Skip(This,cFilters) \ + ( (This)->lpVtbl -> Skip(This,cFilters) ) +#define IEnumFilters_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) +#define IEnumFilters_Clone(This,ppEnum) \ + ( (This)->lpVtbl -> Clone(This,ppEnum) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IMemAllocator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IMemAllocator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IMemAllocator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IMemAllocator_SetProperties(This,pRequest,pActual) \ + ( (This)->lpVtbl -> SetProperties(This,pRequest,pActual) ) +#define IMemAllocator_GetProperties(This,pProps) \ + ( (This)->lpVtbl -> GetProperties(This,pProps) ) +#define IMemAllocator_Commit(This) \ + ( (This)->lpVtbl -> Commit(This) ) +#define IMemAllocator_Decommit(This) \ + ( (This)->lpVtbl -> Decommit(This) ) +#define IMemAllocator_GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags) \ + ( (This)->lpVtbl -> GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags) ) +#define IMemAllocator_ReleaseBuffer(This,pBuffer) \ + ( (This)->lpVtbl -> ReleaseBuffer(This,pBuffer) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IMemInputPin_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IMemInputPin_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IMemInputPin_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IMemInputPin_GetAllocator(This,ppAllocator) \ + ( (This)->lpVtbl -> GetAllocator(This,ppAllocator) ) +#define IMemInputPin_NotifyAllocator(This,pAllocator,bReadOnly) \ + ( (This)->lpVtbl -> NotifyAllocator(This,pAllocator,bReadOnly) ) +#define IMemInputPin_GetAllocatorRequirements(This,pProps) \ + ( (This)->lpVtbl -> GetAllocatorRequirements(This,pProps) ) +#define IMemInputPin_Receive(This,pSample) \ + ( (This)->lpVtbl -> Receive(This,pSample) ) +#define IMemInputPin_ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed) \ + ( (This)->lpVtbl -> ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed) ) +#define IMemInputPin_ReceiveCanBlock(This) \ + ( (This)->lpVtbl -> ReceiveCanBlock(This) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IGraphBuilder_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IGraphBuilder_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IGraphBuilder_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IGraphBuilder_AddFilter(This,pFilter,pName) \ + ( (This)->lpVtbl -> AddFilter(This,pFilter,pName) ) +#define IGraphBuilder_RemoveFilter(This,pFilter) \ + ( (This)->lpVtbl -> RemoveFilter(This,pFilter) ) +#define IGraphBuilder_EnumFilters(This,ppEnum) \ + ( (This)->lpVtbl -> EnumFilters(This,ppEnum) ) +#define IGraphBuilder_FindFilterByName(This,pName,ppFilter) \ + ( (This)->lpVtbl -> FindFilterByName(This,pName,ppFilter) ) +#define IGraphBuilder_ConnectDirect(This,ppinOut,ppinIn,pmt) \ + ( (This)->lpVtbl -> ConnectDirect(This,ppinOut,ppinIn,pmt) ) +#define IGraphBuilder_Reconnect(This,ppin) \ + ( (This)->lpVtbl -> Reconnect(This,ppin) ) +#define IGraphBuilder_Disconnect(This,ppin) \ + ( (This)->lpVtbl -> Disconnect(This,ppin) ) +#define IGraphBuilder_SetDefaultSyncSource(This) \ + ( (This)->lpVtbl -> SetDefaultSyncSource(This) ) +#define IGraphBuilder_Connect(This,ppinOut,ppinIn) \ + ( (This)->lpVtbl -> Connect(This,ppinOut,ppinIn) ) +#define IGraphBuilder_Render(This,ppinOut) \ + ( (This)->lpVtbl -> Render(This,ppinOut) ) +#define IGraphBuilder_RenderFile(This,lpcwstrFile,lpcwstrPlayList) \ + ( (This)->lpVtbl -> RenderFile(This,lpcwstrFile,lpcwstrPlayList) ) +#define IGraphBuilder_AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) \ + ( (This)->lpVtbl -> AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) ) +#define IGraphBuilder_SetLogFile(This,hFile) \ + ( (This)->lpVtbl -> SetLogFile(This,hFile) ) +#define IGraphBuilder_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) +#define IGraphBuilder_ShouldOperationContinue(This) \ + ( (This)->lpVtbl -> ShouldOperationContinue(This) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IEnumMediaTypes_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IEnumMediaTypes_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IEnumMediaTypes_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IEnumMediaTypes_Next(This,cMediaTypes,ppMediaTypes,pcFetched) \ + ( (This)->lpVtbl -> Next(This,cMediaTypes,ppMediaTypes,pcFetched) ) +#define IEnumMediaTypes_Skip(This,cMediaTypes) \ + ( (This)->lpVtbl -> Skip(This,cMediaTypes) ) +#define IEnumMediaTypes_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) +#define IEnumMediaTypes_Clone(This,ppEnum) \ + ( (This)->lpVtbl -> Clone(This,ppEnum) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IMediaControl_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IMediaControl_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IMediaControl_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IMediaControl_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) +#define IMediaControl_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) +#define IMediaControl_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) +#define IMediaControl_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) +#define IMediaControl_Run(This) \ + ( (This)->lpVtbl -> Run(This) ) +#define IMediaControl_Pause(This) \ + ( (This)->lpVtbl -> Pause(This) ) +#define IMediaControl_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) +#define IMediaControl_GetState(This,msTimeout,pfs) \ + ( (This)->lpVtbl -> GetState(This,msTimeout,pfs) ) +#define IMediaControl_RenderFile(This,strFilename) \ + ( (This)->lpVtbl -> RenderFile(This,strFilename) ) +#define IMediaControl_AddSourceFilter(This,strFilename,ppUnk) \ + ( (This)->lpVtbl -> AddSourceFilter(This,strFilename,ppUnk) ) +#define IMediaControl_get_FilterCollection(This,ppUnk) \ + ( (This)->lpVtbl -> get_FilterCollection(This,ppUnk) ) +#define IMediaControl_get_RegFilterCollection(This,ppUnk) \ + ( (This)->lpVtbl -> get_RegFilterCollection(This,ppUnk) ) +#define IMediaControl_StopWhenReady(This) \ + ( (This)->lpVtbl -> StopWhenReady(This) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IAMVideoProcAmp_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IAMVideoProcAmp_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IAMVideoProcAmp_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IAMVideoProcAmp_GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags) \ + ( (This)->lpVtbl -> GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags) ) +#define IAMVideoProcAmp_Set(This,Property,lValue,Flags) \ + ( (This)->lpVtbl -> Set(This,Property,lValue,Flags) ) +#define IAMVideoProcAmp_Get(This,Property,lValue,Flags) \ + ( (This)->lpVtbl -> Get(This,Property,lValue,Flags) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IFileSinkFilter_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IFileSinkFilter_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IFileSinkFilter_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IFileSinkFilter_SetFileName(This,pszFileName,pmt) \ + ( (This)->lpVtbl -> SetFileName(This,pszFileName,pmt) ) +#define IFileSinkFilter_GetCurFile(This,ppszFileName,pmt) \ + ( (This)->lpVtbl -> GetCurFile(This,ppszFileName,pmt) ) +#endif /* COBJMACROS */ + +#ifdef COBJMACROS +#define IAMCopyCaptureFileProgress_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define IAMCopyCaptureFileProgress_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define IAMCopyCaptureFileProgress_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define IAMCopyCaptureFileProgress_Progress(This,iProgress) \ + ( (This)->lpVtbl -> Progress(This,iProgress) ) +#endif /* COBJMACROS */ + + +#ifdef COBJMACROS +#define ICaptureGraphBuilder2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) +#define ICaptureGraphBuilder2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) +#define ICaptureGraphBuilder2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) +#define ICaptureGraphBuilder2_SetFiltergraph(This,pfg) \ + ( (This)->lpVtbl -> SetFiltergraph(This,pfg) ) +#define ICaptureGraphBuilder2_GetFiltergraph(This,ppfg) \ + ( (This)->lpVtbl -> GetFiltergraph(This,ppfg) ) +#define ICaptureGraphBuilder2_SetOutputFileName(This,pType,lpstrFile,ppf,ppSink) \ + ( (This)->lpVtbl -> SetOutputFileName(This,pType,lpstrFile,ppf,ppSink) ) +#define ICaptureGraphBuilder2_FindInterface(This,pCategory,pType,pf,riid,ppint) \ + ( (This)->lpVtbl -> FindInterface(This,pCategory,pType,pf,riid,ppint) ) +#define ICaptureGraphBuilder2_RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer) \ + ( (This)->lpVtbl -> RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer) ) +#define ICaptureGraphBuilder2_ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) \ + ( (This)->lpVtbl -> ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) ) +#define ICaptureGraphBuilder2_AllocCapFile(This,lpstr,dwlSize) \ + ( (This)->lpVtbl -> AllocCapFile(This,lpstr,dwlSize) ) +#define ICaptureGraphBuilder2_CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback) \ + ( (This)->lpVtbl -> CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback) ) +#define ICaptureGraphBuilder2_FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin) \ + ( (This)->lpVtbl -> FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin) ) +#endif /* COBJMACROS */ + +#endif // _MARU_CAMERA_INTERFACE_H_ diff --git a/tizen/src/hw/maru_camera_win32_pci.c b/tizen/src/hw/maru_camera_win32_pci.c index 9dcb38c2a4..aeae0bd694 100644 --- a/tizen/src/hw/maru_camera_win32_pci.c +++ b/tizen/src/hw/maru_camera_win32_pci.c @@ -1,744 +1,2004 @@ -/* - * Implementation of MARU Virtual Camera device by PCI bus on Windows. - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: - * JinHyung Jo - * YeongKyoon Lee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - - -#include "qemu-common.h" -#include "maru_camera_common.h" -#include "pci.h" -#include "kvm.h" -#include "tizen/src/debug_ch.h" - -#include "windows.h" -#include "basetyps.h" -#include "mmsystem.h" - -MULTI_DEBUG_CHANNEL(tizen, camera_win32); - -// V4L2 defines copy from videodev2.h -#define V4L2_CTRL_FLAG_SLIDER 0x0020 - -#define V4L2_CTRL_CLASS_USER 0x00980000 -#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) -#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) -#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) -#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) -#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) - -#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ -#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ - -enum { - HWC_OPEN, - HWC_CLOSE, - HWC_START, - HWC_STOP, - HWC_S_FPS, - HWC_G_FPS, - HWC_S_FMT, - HWC_G_FMT, - HWC_TRY_FMT, - HWC_ENUM_FMT, - HWC_QCTRL, - HWC_S_CTRL, - HWC_G_CTRL, - HWC_ENUM_FSIZES, - HWC_ENUM_INTERVALS -}; - -typedef enum tagVideoProcAmpProperty { - VideoProcAmp_Brightness, - VideoProcAmp_Contrast, - VideoProcAmp_Hue, - VideoProcAmp_Saturation, - VideoProcAmp_Sharpness, - VideoProcAmp_Gamma, - VideoProcAmp_ColorEnable, - VideoProcAmp_WhiteBalance, - VideoProcAmp_BacklightCompensation, - VideoProcAmp_Gain -} VideoProcAmpProperty; - -typedef struct tagHWCParam { - long val1; - long val2; - long val3; - long val4; - long val5; -} HWCParam; - -typedef struct tagMaruCamConvertPixfmt { - uint32_t fmt; /* fourcc */ - uint32_t bpp; /* bits per pixel, 0 for compressed formats */ - uint32_t needs_conversion; -} MaruCamConvertPixfmt; - -static MaruCamConvertPixfmt supported_dst_pixfmts[] = { - { V4L2_PIX_FMT_YUYV, 16, 0 }, - { V4L2_PIX_FMT_YUV420, 12, 0 }, - { V4L2_PIX_FMT_YVU420, 12, 0 }, -}; - -typedef struct tagMaruCamConvertFrameInfo { - uint32_t width; - uint32_t height; -} MaruCamConvertFrameInfo; - -static MaruCamConvertFrameInfo supported_dst_frames[] = { - { 640, 480 }, - { 352, 288 }, - { 320, 240 }, - { 176, 144 }, - { 160, 120 }, -}; - -#define MARUCAM_CTRL_VALUE_MAX 20 -#define MARUCAM_CTRL_VALUE_MIN 1 -#define MARUCAM_CTRL_VALUE_MID 10 -#define MARUCAM_CTRL_VALUE_STEP 1 - -struct marucam_qctrl { - uint32_t id; - uint32_t hit; - long min; - long max; - long step; - long init_val; -}; - -static struct marucam_qctrl qctrl_tbl[] = { - { V4L2_CID_BRIGHTNESS, 0, }, - { V4L2_CID_CONTRAST, 0, }, - { V4L2_CID_SATURATION,0, }, - { V4L2_CID_SHARPNESS, 0, }, -}; - -typedef int (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer); -typedef HRESULT (STDAPICALLTYPE *CTRLFN)(UINT, UINT, LPVOID); -typedef HRESULT (STDAPICALLTYPE *SETCALLBACKFN)(CallbackFn); - - -static HINSTANCE g_hInst = NULL; -static MaruCamState *g_state = NULL; - -static CTRLFN MaruCamCtrl; -static SETCALLBACKFN MaruCamSetCallbackFn; - -static uint32_t cur_fmt_idx = 0; -static uint32_t cur_frame_idx = 0; - -void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest, - uint32_t width, uint32_t height, uint32_t yvu); - - -static long value_convert_from_guest(long min, long max, long value) -{ - double rate = 0.0; - long dist = 0, ret = 0; - - dist = max - min; - - if (dist < MARUCAM_CTRL_VALUE_MAX) { - rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; - ret = min + (int32_t)(value / rate); - } else { - rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; - ret = min + (int32_t)(rate * value); - } - return ret; -} - -static long value_convert_to_guest(long min, long max, long value) -{ - double rate = 0.0; - long dist = 0, ret = 0; - - dist = max - min; - - if (dist < MARUCAM_CTRL_VALUE_MAX) { - rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; - ret = (int32_t)((double)(value - min) * rate); - } else { - rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; - ret = (int32_t)((double)(value - min) / rate); - } - - return ret; -} - -static int STDAPICALLTYPE marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer) -{ - static uint32_t index = 0; - uint32_t width, height; - width = supported_dst_frames[cur_frame_idx].width; - height = supported_dst_frames[cur_frame_idx].height; - void *buf = g_state->vaddr + (g_state->buf_size * index); - - switch (supported_dst_pixfmts[cur_fmt_idx].fmt) { - case V4L2_PIX_FMT_YUV420: - v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 0); - break; - case V4L2_PIX_FMT_YVU420: - v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1); - break; - case V4L2_PIX_FMT_YUYV: - memcpy(buf, (void*)pBuffer, dwSize); - break; - } - index = !index; - - if (g_state->req_frame) { - qemu_irq_raise(g_state->dev.irq[2]); - g_state->req_frame = 0; - } - return 1; -} - -// MARUCAM_CMD_INIT -void marucam_device_init(MaruCamState* state) -{ - MaruCamThreadInfo *thread = state->thread; - - pthread_cond_init(&thread->thread_cond, NULL); - pthread_mutex_init(&thread->mutex_lock, NULL); - - g_state = state; -} - -// MARUCAM_CMD_OPEN -void marucam_device_open(MaruCamState* state) -{ - HRESULT hr; - MaruCamParam *param = state->thread->param; - param->top = 0; - - g_hInst = LoadLibrary("hwcfilter.dll"); - - if (!g_hInst) { - g_hInst = LoadLibrary("bin\\hwcfilter.dll"); - if (!g_hInst) { - ERR("load library failed!!!!\n"); - param->errCode = EINVAL; - return; - } - } - - MaruCamCtrl = (CTRLFN)GetProcAddress(g_hInst, "HWCCtrl"); - if (!MaruCamCtrl) { - ERR("HWCCtrl get failed!!!\n"); - FreeLibrary(g_hInst); - param->errCode = EINVAL; - return; - } - - MaruCamSetCallbackFn = (SETCALLBACKFN)GetProcAddress(g_hInst, "HWCSetCallback"); - if (!MaruCamSetCallbackFn) { - ERR("HWCSetCallback get failed!!!\n"); - FreeLibrary(g_hInst); - param->errCode = EINVAL; - return; - } - - hr = MaruCamCtrl(HWC_OPEN, 0, NULL); - if (FAILED(hr)) { - param->errCode = EINVAL; - FreeLibrary(g_hInst); - ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr); - return; - } - hr = MaruCamSetCallbackFn((CallbackFn)marucam_device_callbackfn); - if (FAILED(hr)) { - param->errCode = EINVAL; - MaruCamCtrl(HWC_CLOSE, 0, NULL); - FreeLibrary(g_hInst); - ERR("call back function set failed!!!, [HRESULT : 0x%x]\n", hr); - } - - TRACE("camera device open success!!!, [HRESULT : 0x%x]\n", hr); -} - -// MARUCAM_CMD_CLOSE -void marucam_device_close(MaruCamState* state) -{ - HRESULT hr; - MaruCamParam *param = state->thread->param; - param->top = 0; - hr = MaruCamCtrl(HWC_CLOSE, 0, NULL); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("camera device close failed!!!, [HRESULT : 0x%x]\n", hr); - } - FreeLibrary(g_hInst); - TRACE("camera device close success!!!, [HRESULT : 0x%x]\n", hr); -} - -// MARUCAM_CMD_START_PREVIEW -void marucam_device_start_preview(MaruCamState* state) -{ - HRESULT hr; - uint32_t width, height; - MaruCamParam *param = state->thread->param; - TRACE("marucam_device_start_preview\n"); - param->top = 0; - hr = MaruCamCtrl(HWC_START, 0, NULL); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("start preview failed!!!, [HRESULT : 0x%x]\n", hr); - return; - } - pthread_mutex_lock(&state->thread->mutex_lock); - state->streamon = 1; - pthread_mutex_unlock(&state->thread->mutex_lock); - - width = supported_dst_frames[cur_frame_idx].width; - height = supported_dst_frames[cur_frame_idx].height; - state->buf_size = height * ((width * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3); -} - -// MARUCAM_CMD_STOP_PREVIEW -void marucam_device_stop_preview(MaruCamState* state) -{ - HRESULT hr; - MaruCamParam *param = state->thread->param; - TRACE("marucam_device_stop_preview\n"); - param->top = 0; - hr = MaruCamCtrl(HWC_STOP, 0, NULL); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("stop preview failed!!!, [HRESULT : 0x%x]\n", hr); - } - pthread_mutex_lock(&state->thread->mutex_lock); - state->streamon = 0; - pthread_mutex_unlock(&state->thread->mutex_lock); - state->buf_size = 0; -} - -// MARUCAM_CMD_S_PARAM -void marucam_device_s_param(MaruCamState* state) -{ - MaruCamParam *param = state->thread->param; - - param->top = 0; - TRACE("setting fps : %d/%d\n", param->stack[0], param->stack[1]); -} - -// MARUCAM_CMD_G_PARAM -void marucam_device_g_param(MaruCamState* state) -{ - MaruCamParam *param = state->thread->param; - - param->top = 0; - TRACE("getting fps : 30/1\n"); - - param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME - param->stack[1] = 1; // numerator; - param->stack[2] = 30; // denominator; -} - -// MARUCAM_CMD_S_FMT -void marucam_device_s_fmt(MaruCamState* state) -{ - uint32_t width, height, pixfmt, pidx, fidx; - MaruCamParam *param = state->thread->param; - - param->top = 0; - width = param->stack[0]; // width - height = param->stack[1]; // height - pixfmt = param->stack[2]; // pixelformat - - for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) { - if ((supported_dst_frames[fidx].width == width) && - (supported_dst_frames[fidx].height == height)) { - break; - } - } - if (fidx == ARRAY_SIZE(supported_dst_frames)) { - param->errCode = EINVAL; - return; - } - for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) { - if (supported_dst_pixfmts[pidx].fmt == pixfmt) { - break; - } - } - if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; - return; - } - - if ((supported_dst_frames[cur_frame_idx].width != width) && - (supported_dst_frames[cur_frame_idx].height != height)) { - HWCParam inParam = {0,}; - inParam.val1 = width; - inParam.val2 = height; - HRESULT hr = MaruCamCtrl(HWC_S_FMT, sizeof(HWCParam), &inParam); - if (FAILED(hr)) { - param->errCode = EINVAL; - return; - } - } - - param->stack[0] = width; - param->stack[1] = height; - param->stack[2] = 1; // V4L2_FIELD_NONE - param->stack[3] = pixfmt; - // bytes per line = (width * bpp) / 8 - param->stack[4] = (width * supported_dst_pixfmts[pidx].bpp) >> 3; - param->stack[5] = param->stack[4] * height; // height * bytesperline - param->stack[6] = 0; - param->stack[7] = 0; - - cur_frame_idx = fidx; - cur_fmt_idx = pidx; -} - -// MARUCAM_CMD_G_FMT -void marucam_device_g_fmt(MaruCamState* state) -{ - MaruCamParam *param = state->thread->param; - - param->top = 0; - - param->stack[0] = supported_dst_frames[cur_frame_idx].width; // width - param->stack[1] = supported_dst_frames[cur_frame_idx].height; // height - param->stack[2] = 1; // V4L2_FIELD_NONE - param->stack[3] = supported_dst_pixfmts[cur_fmt_idx].fmt; // pixelformat - // bytes per line = (width * bpp) / 8 - param->stack[4] = (param->stack[0] * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3; - param->stack[5] = param->stack[1] * param->stack[4]; // height * bytesperline - param->stack[6] = 0; - param->stack[7] = 0; -} - -void marucam_device_try_fmt(MaruCamState* state) -{ - uint32_t width, height, pixfmt, i; - MaruCamParam *param = state->thread->param; - - param->top = 0; - width = param->stack[0]; // width - height = param->stack[1]; // height - pixfmt = param->stack[2]; // pixelformat - - for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) { - if ((supported_dst_frames[i].width == width) && - (supported_dst_frames[i].height == height)) { - break; - } - } - if (i == ARRAY_SIZE(supported_dst_frames)) { - param->errCode = EINVAL; - return; - } - for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) { - if (supported_dst_pixfmts[i].fmt == pixfmt) { - break; - } - } - if (i == ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; - return; - } - - param->stack[0] = width; - param->stack[1] = height; - param->stack[2] = 1; // V4L2_FIELD_NONE - param->stack[3] = pixfmt; - // bytes per line = (width * bpp) / 8 - param->stack[4] = (width * supported_dst_pixfmts[i].bpp) >> 3; - param->stack[5] = param->stack[4] * height; // height * bytesperline - param->stack[6] = 0; - param->stack[7] = 0; -} - -void marucam_device_enum_fmt(MaruCamState* state) -{ - uint32_t index; - MaruCamParam *param = state->thread->param; - - param->top = 0; - index = param->stack[0]; - - if (index >= ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; - return; - } - param->stack[1] = 0; // flags = NONE; - param->stack[2] = supported_dst_pixfmts[index].fmt; // pixelformat; - /* set description */ - switch (supported_dst_pixfmts[index].fmt) { - case V4L2_PIX_FMT_YUYV: - memcpy(¶m->stack[3], "YUY2", 32); - break; - case V4L2_PIX_FMT_YUV420: - memcpy(¶m->stack[3], "YU12", 32); - break; - case V4L2_PIX_FMT_YVU420: - memcpy(¶m->stack[3], "YV12", 32); - break; - } -} - -void marucam_device_qctrl(MaruCamState* state) -{ - HRESULT hr; - uint32_t id, i; - HWCParam inParam = {0,}; - char name[32] = {0,}; - MaruCamParam *param = state->thread->param; - - param->top = 0; - id = param->stack[0]; - - switch (id) { - case V4L2_CID_BRIGHTNESS: - TRACE("V4L2_CID_BRIGHTNESS\n"); - inParam.val1 = VideoProcAmp_Brightness; - memcpy((void*)name, (void*)"brightness", 32); - i = 0; - break; - case V4L2_CID_CONTRAST: - TRACE("V4L2_CID_CONTRAST\n"); - inParam.val1 = VideoProcAmp_Contrast; - memcpy((void*)name, (void*)"contrast", 32); - i = 1; - break; - case V4L2_CID_SATURATION: - TRACE("V4L2_CID_SATURATION\n"); - inParam.val1 = VideoProcAmp_Saturation; - memcpy((void*)name, (void*)"saturation", 32); - i = 2; - break; - case V4L2_CID_SHARPNESS: - TRACE("V4L2_CID_SHARPNESS\n"); - inParam.val1 = VideoProcAmp_Sharpness; - memcpy((void*)name, (void*)"sharpness", 32); - i = 3; - break; - default: - param->errCode = EINVAL; - return; - } - hr = MaruCamCtrl(HWC_QCTRL, sizeof(inParam), &inParam); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("failed to query video controls [HRESULT : 0x%x]\n", hr); - return; - } else { - qctrl_tbl[i].hit = 1; - qctrl_tbl[i].min = inParam.val2; - qctrl_tbl[i].max = inParam.val3; - qctrl_tbl[i].step = inParam.val4; - qctrl_tbl[i].init_val = inParam.val5; - - if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) { - inParam.val2 = 0; - } else { - inParam.val2 = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2; - } - hr = MaruCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr); - return; - } - } - - param->stack[0] = id; - param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum - param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum - param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step - param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value - param->stack[5] = V4L2_CTRL_FLAG_SLIDER; - /* name field setting */ - memcpy(¶m->stack[6], (void*)name, sizeof(name)/sizeof(name[0])); -} - -void marucam_device_s_ctrl(MaruCamState* state) -{ - HRESULT hr; - uint32_t i; - HWCParam inParam = {0,}; - MaruCamParam *param = state->thread->param; - - param->top = 0; - - switch (param->stack[0]) { - case V4L2_CID_BRIGHTNESS: - i = 0; - inParam.val1 = VideoProcAmp_Brightness; - break; - case V4L2_CID_CONTRAST: - i = 1; - inParam.val1 = VideoProcAmp_Contrast; - break; - case V4L2_CID_SATURATION: - i = 2; - inParam.val1 = VideoProcAmp_Saturation; - break; - case V4L2_CID_SHARPNESS: - i = 3; - inParam.val1 = VideoProcAmp_Sharpness; - break; - default: - param->errCode = EINVAL; - return; - } - inParam.val2 = value_convert_from_guest(qctrl_tbl[i].min, - qctrl_tbl[i].max, (long)param->stack[1]); - hr = MaruCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr); - return; - } -} - -void marucam_device_g_ctrl(MaruCamState* state) -{ - HRESULT hr; - uint32_t i; - HWCParam inParam = {0,}; - MaruCamParam *param = state->thread->param; - - param->top = 0; - switch (param->stack[0]) { - case V4L2_CID_BRIGHTNESS: - i = 0; - inParam.val1 = VideoProcAmp_Brightness; - break; - case V4L2_CID_CONTRAST: - i = 1; - inParam.val1 = VideoProcAmp_Contrast; - break; - case V4L2_CID_SATURATION: - i = 2; - inParam.val1 = VideoProcAmp_Saturation; - break; - case V4L2_CID_SHARPNESS: - i = 3; - inParam.val1 = VideoProcAmp_Sharpness; - break; - default: - param->errCode = EINVAL; - return; - } - - hr = MaruCamCtrl(HWC_G_CTRL, sizeof(inParam), &inParam); - if (FAILED(hr)) { - param->errCode = EINVAL; - ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr); - return; - } - param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min, - qctrl_tbl[i].max, inParam.val2); -} - -void marucam_device_enum_fsizes(MaruCamState* state) -{ - uint32_t index, pixfmt, i; - MaruCamParam *param = state->thread->param; - - param->top = 0; - index = param->stack[0]; - pixfmt = param->stack[1]; - - if (index >= ARRAY_SIZE(supported_dst_frames)) { - param->errCode = EINVAL; - return; - } - for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) { - if (supported_dst_pixfmts[i].fmt == pixfmt) - break; - } - - if (i == ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; - return; - } - - param->stack[0] = supported_dst_frames[index].width; - param->stack[1] = supported_dst_frames[index].height; -} - -void marucam_device_enum_fintv(MaruCamState* state) -{ - MaruCamParam *param = state->thread->param; - - param->top = 0; - - // switch by index(param->stack[0]) - switch (param->stack[0]) { - case 0: - param->stack[1] = 30; // denominator - break; - default: - param->errCode = EINVAL; - return; - } - param->stack[0] = 1; // numerator -} - -void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest, - uint32_t width, uint32_t height, uint32_t yvu) -{ - uint32_t i, j; - const unsigned char *src1; - unsigned char *udest, *vdest; - - /* copy the Y values */ - src1 = src; - for (i = 0; i < height; i++) { - for (j = 0; j < width; j += 2) { - *dest++ = src1[0]; - *dest++ = src1[2]; - src1 += 4; - } - } - - /* copy the U and V values */ - src++; /* point to V */ - src1 = src + width * 2; /* next line */ - if (yvu) { - vdest = dest; - udest = dest + width * height / 4; - } else { - udest = dest; - vdest = dest + width * height / 4; - } - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - *udest++ = ((int) src[0] + src1[0]) / 2; /* U */ - *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */ - src += 4; - src1 += 4; - } - src = src1; - src1 += width * 2; - } -} +/* + * Implementation of MARU Virtual Camera device by PCI bus on Windows. + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + + +#include "qemu-common.h" +#include "maru_camera_common.h" +#include "tizen/src/debug_ch.h" + +#define CINTERFACE +#define COBJMACROS +#include "ocidl.h" +#include "errors.h" /* for VFW_E_XXXX */ +#include "mmsystem.h" /* for MAKEFOURCC macro */ +#include "maru_camera_win32_interface.h" + +MULTI_DEBUG_CHANNEL(tizen, camera_win32); + +/* + * COM Interface implementations + * + */ + +#define SAFE_RELEASE(x) { if (x) x->lpVtbl->Release(x); x = NULL; } + +typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer); + +/* + * HWCGrabCallback + */ + +typedef struct HWCGrabCallback +{ + IGrabCallback IGrabCallback_iface; + long m_cRef; + CallbackFn m_pCallback; + STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn); +} HWCGrabCallback; + +static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface) +{ + return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface); +} + +static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown)) { + *ppv = (IUnknown*)iface; + } else if (IsEqualIID(riid, &IID_IGrabCallback)) { + *ppv = (IGrabCallback*)iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IGrabCallback_AddRef(iface); + return S_OK; +} + +static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface) +{ + HWCGrabCallback *This = impl_from_IGrabCallback(iface); + + return InterlockedIncrement(&This->m_cRef); +} + +static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface) +{ + HWCGrabCallback *This = impl_from_IGrabCallback(iface); + + if( InterlockedDecrement(&This->m_cRef) == 0) + { + This->m_pCallback = NULL; + g_free((void*)This); + return 0; + } + + return This->m_cRef; +} + +static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface, ULONG dwSize, BYTE *pBuffer) +{ + HWCGrabCallback *This = impl_from_IGrabCallback(iface); + + if (This->m_pCallback) { + This->m_pCallback(dwSize, pBuffer); + return S_OK; + } + + return E_FAIL; +} + +static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface, CallbackFn pCallbackFn) +{ + HWCGrabCallback *This = impl_from_IGrabCallback(iface); + + This->m_pCallback = pCallbackFn; + return S_OK; +} + +static IGrabCallbackVtbl HWCGrabCallback_Vtbl = +{ + HWCGrabCallback_QueryInterface, + HWCGrabCallback_AddRef, + HWCGrabCallback_Release, + HWCGrabCallback_Grab +}; + +static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv) +{ + HWCGrabCallback *This = (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback)); + + if (!This) { + return E_OUTOFMEMORY; + } + + This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl; + This->m_cRef = 1; + This->m_pCallback = NULL; + This->SetCallback = HWCGrabCallback_SetCallback; + *ppv = &This->IGrabCallback_iface; + return S_OK; +} + +/* + * HWCPin + */ + +typedef struct HWCInPin +{ + IPin IPin_iface; + IMemInputPin IMemInputPin_iface; + IBaseFilter *m_pCFilter; + IPin *m_pConnectedPin; + IGrabCallback *m_pCallback; + BOOL m_bReadOnly; + long m_cRef; + STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB); +} HWCInPin; + +static inline HWCInPin *impl_from_IPin(IPin *iface) +{ + return CONTAINING_RECORD(iface, HWCInPin, IPin_iface); +} + +static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface) +{ + return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface); +} + +static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv) +{ + HWCInPin *This = impl_from_IPin(iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) { + *ppv = &This->IPin_iface; + IPin_AddRef((IPin*)*ppv); + } else if (IsEqualIID(riid, &IID_IMemInputPin)) { + *ppv = &This->IMemInputPin_iface; + IPin_AddRef((IMemInputPin*)*ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface) +{ + HWCInPin *This = impl_from_IPin(iface); + + return InterlockedIncrement(&This->m_cRef); +} + +static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface) +{ + HWCInPin *This = impl_from_IPin(iface); + + if( InterlockedDecrement(&This->m_cRef) == 0) + { + if (This->m_pCFilter) { + IBaseFilter_Release(This->m_pCFilter); + This->m_pCFilter = NULL; + } + if (This->m_pCallback) { + IGrabCallback_Release(This->m_pCallback); + This->m_pCallback = NULL; + } + if (This->m_pConnectedPin) { + IPin_Release(This->m_pConnectedPin); + This->m_pConnectedPin = NULL; + } + g_free((void*)This); + return 0; + } + return This->m_cRef; +} + +static STDMETHODIMP HWCPin_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) +{ + if ( !pmt ) + return S_OK; + return S_FALSE; +} + +static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector, const AM_MEDIA_TYPE *pmt) +{ + HWCInPin *This = impl_from_IPin(iface); + + if (pConnector == NULL || pmt == NULL) + return E_POINTER; + + if (This->m_pConnectedPin) { + return VFW_E_ALREADY_CONNECTED; + } + FILTER_STATE fs; + IBaseFilter_GetState(This->m_pCFilter, 0, &fs); + if (fs != State_Stopped) { + return VFW_E_NOT_STOPPED; + } + PIN_DIRECTION pd; + IPin_QueryDirection(pConnector, &pd); + if (pd == PINDIR_INPUT) { + return VFW_E_INVALID_DIRECTION; + } + + This->m_pConnectedPin = pConnector; + IPin_AddRef(This->m_pConnectedPin); + return S_OK; +} + +static STDMETHODIMP HWCPin_Disconnect(IPin *iface) +{ + HWCInPin *This = impl_from_IPin(iface); + + HRESULT hr; + if (This->m_pConnectedPin == NULL) { + hr = S_FALSE; + } else { + IPin_Release(This->m_pConnectedPin); + This->m_pConnectedPin = NULL; + hr = S_OK; + } + return hr; +} + +static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **pPin) +{ + HWCInPin *This = impl_from_IPin(iface); + + if (pPin == NULL) + return E_POINTER; + + if (This->m_pConnectedPin == NULL) { + return VFW_E_NOT_CONNECTED; + } else { + *pPin = This->m_pConnectedPin; + IPin_AddRef(This->m_pConnectedPin); + } + return S_OK; +} + +static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt) +{ + if (pmt == NULL) { + return E_POINTER; + } + return VFW_E_NOT_CONNECTED; +} + +static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo) +{ + HWCInPin *This = impl_from_IPin(iface); + + if (pInfo == NULL) + return E_POINTER; + + pInfo->pFilter = This->m_pCFilter; + if (This->m_pCFilter) { + IBaseFilter_AddRef(This->m_pCFilter); + } + memcpy((void*)pInfo->achName, (void*)HWCPinName, sizeof(HWCPinName)); + pInfo->dir = PINDIR_INPUT; + return S_OK; +} + +static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir) +{ + if (pPinDir == NULL) + return E_POINTER; + *pPinDir = PINDIR_INPUT; + return S_OK; +} + +static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id) +{ + if (Id == NULL) + return E_POINTER; + PVOID pId = CoTaskMemAlloc(sizeof(HWCPinName)); + memcpy((void*)pId, (void*)HWCPinName, sizeof(HWCPinName)); + *Id = (LPWSTR)pId; + return S_OK; +} + +static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) +{ + if (pmt == NULL) + return E_POINTER; + return S_OK; +} + +static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) +{ + if (ppEnum == NULL) + return E_POINTER; + return E_NOTIMPL; +} + +static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface, IPin **ppPin, ULONG *nPin) +{ + return E_NOTIMPL; +} + +static STDMETHODIMP HWCPin_EndOfStream(IPin *iface) +{ + return S_OK; +} + +static STDMETHODIMP HWCPin_BeginFlush(IPin *iface) +{ + return S_OK; +} + +static STDMETHODIMP HWCPin_EndFlush(IPin *iface) +{ + return S_OK; +} + +static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + return S_OK; +} + +static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv) +{ + HWCInPin *This = impl_from_IMemInputPin(iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMemInputPin)) { + *ppv = &This->IMemInputPin_iface; + IMemInputPin_AddRef((IMemInputPin*)*ppv); + } else if (IsEqualIID(riid, &IID_IPin)) { + *ppv = &This->IPin_iface; + IPin_AddRef((IPin*)*ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface) +{ + HWCInPin *This = impl_from_IMemInputPin(iface); + + return InterlockedIncrement(&This->m_cRef); +} + +static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface) +{ + HWCInPin *This = impl_from_IMemInputPin(iface); + + if( InterlockedDecrement(&This->m_cRef) == 0) + { + if (This->m_pCFilter) { + IBaseFilter_Release(This->m_pCFilter); + This->m_pCFilter = NULL; + } + if (This->m_pCallback) { + IGrabCallback_Release(This->m_pCallback); + This->m_pCallback = NULL; + } + if (This->m_pConnectedPin) { + IPin_Release(This->m_pConnectedPin); + This->m_pConnectedPin = NULL; + } + g_free((void*)This); + return 0; + } + return This->m_cRef; +} + +static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **ppAllocator) +{ + if (ppAllocator == NULL) + return E_POINTER; + return VFW_E_NO_ALLOCATOR; +} + +static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly) +{ + if (pAllocator == NULL) + return E_POINTER; + + return NOERROR; +} + +static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps) +{ + return E_NOTIMPL; +} + +static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface, IMediaSample *pSample) +{ + HWCInPin *This = impl_from_IMemInputPin(iface); + + if (pSample == NULL) + return E_POINTER; + if (This->m_pCallback != NULL) { + HRESULT hr; + BYTE* pBuffer = NULL; + BYTE* pTmp_Buffer = NULL; /* is this required? */ + DWORD dwSize = 0; + dwSize = IMediaSample_GetSize(pSample); + hr = IMediaSample_GetPointer(pSample, &pBuffer); + if (FAILED(hr)) + return hr; + + pTmp_Buffer = (BYTE *)g_malloc0((size_t)dwSize); + if (!pTmp_Buffer) + return E_OUTOFMEMORY; + memcpy((void*)pTmp_Buffer, (void*)pBuffer, (size_t)dwSize); + + hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pTmp_Buffer); + if (FAILED(hr)) + return hr; + } + return S_OK; +} + +static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **pSamples, long nSamples, long *nSamplesProcessed) +{ + HRESULT hr = S_OK; + + if (pSamples == NULL) + return E_POINTER; + + *nSamplesProcessed = 0; + + while (nSamples-- > 0) + { + hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]); + if (hr != S_OK) + break; + (*nSamplesProcessed)++; + } + return hr; +} + +static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface) +{ + return S_FALSE; +} + +static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB) +{ + HWCInPin *This = impl_from_IPin(iface); + + if (pCaptureCB == NULL) { + IGrabCallback_Release(This->m_pCallback); + This->m_pCallback = NULL; + } else { + This->m_pCallback = pCaptureCB; + IGrabCallback_AddRef(This->m_pCallback); + } + + return S_OK; +} + + +static IPinVtbl HWCPin_Vtbl = +{ + HWCPin_QueryInterface, + HWCPin_AddRef, + HWCPin_Release, + HWCPin_Connect, + HWCPin_ReceiveConnection, + HWCPin_Disconnect, + HWCPin_ConnectedTo, + HWCPin_ConnectionMediaType, + HWCPin_QueryPinInfo, + HWCPin_QueryDirection, + HWCPin_QueryId, + HWCPin_QueryAccept, + HWCPin_EnumMediaTypes, + HWCPin_QueryInternalConnections, + HWCPin_EndOfStream, + HWCPin_BeginFlush, + HWCPin_EndFlush, + HWCPin_NewSegment +}; + +static IMemInputPinVtbl HWCMemInputPin_Vtbl = +{ + HWCMemInputPin_QueryInterface, + HWCMemInputPin_AddRef, + HWCMemInputPin_Release, + HWCMemInputPin_GetAllocator, + HWCMemInputPin_NotifyAllocator, + HWCMemInputPin_GetAllocatorRequirements, + HWCMemInputPin_Receive, + HWCMemInputPin_ReceiveMultiple, + HWCMemInputPin_ReceiveCanBlock +}; + +static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv) +{ + HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin)); + + if (!This) { + return E_OUTOFMEMORY; + } + + This->IPin_iface.lpVtbl = &HWCPin_Vtbl; + This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl; + This->m_bReadOnly = FALSE; + This->m_pCFilter = pFilter; + if (This->m_pCFilter) { + IBaseFilter_AddRef(This->m_pCFilter); + } + This->m_pConnectedPin = NULL; + This->m_pCallback = NULL; + This->m_cRef = 1; + This->SetGrabCallbackIF = HWCPin_SetCallback; + *ppv = &This->IPin_iface; + + return S_OK; +} + +/* + * HWCEnumPins + */ + +typedef struct HWCEnumPins +{ + IEnumPins IEnumPins_iface; + IBaseFilter *m_pFilter; + int m_nPos; + long m_cRef; +} HWCEnumPins; + +static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface) +{ + return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface); +} + +static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppv) +{ + if (ppv == NULL) + return E_POINTER; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) { + *ppv = iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IEnumPins_AddRef(iface); + return S_OK; +} + +static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + + return InterlockedIncrement(&This->m_cRef); +} + +static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + + if (InterlockedDecrement(&This->m_cRef) == 0) { + if (This->m_pFilter) { + IBaseFilter_Release(This->m_pFilter); + This->m_pFilter = NULL; + } + This->m_nPos = 0; + g_free((void*)This); + return 0; + } + return This->m_cRef; +} + +static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins, IPin **ppPins, + ULONG *pcFetched) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + + if (ppPins == NULL) + return E_POINTER; + + ULONG fetched; + if (This->m_nPos < 1 && cPins > 0) { + IPin *pPin; + IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin); + *ppPins = pPin; + IPin_AddRef(pPin); + fetched = 1; + This->m_nPos++; + } else { + fetched = 0; + } + + if (pcFetched != NULL ) { + *pcFetched = fetched; + } + + return ( fetched == cPins ) ? S_OK : S_FALSE; +} + +static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + This->m_nPos += cPins; + return ( This->m_nPos >= 1 ) ? S_FALSE : S_OK; +} + +static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + This->m_nPos = 0; + return S_OK; +} + +static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter, int nPos, IEnumPins **ppv); + +static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum) +{ + HWCEnumPins *This = impl_from_IEnumPins(iface); + + if (ppEnum == NULL) + return E_POINTER; + + HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum); + if (*ppEnum == NULL) { + return E_OUTOFMEMORY; + } + + return S_OK; +} + +static IEnumPinsVtbl HWCEnumPins_Vtbl = +{ + HWCEnumPins_QueryInterface, + HWCEnumPins_AddRef, + HWCEnumPins_Release, + HWCEnumPins_Next, + HWCEnumPins_Skip, + HWCEnumPins_Reset, + HWCEnumPins_Clone +}; + + +static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter, int nPos, IEnumPins **ppv) +{ + HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins)); + + if (!This) { + return E_OUTOFMEMORY; + } + + This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl; + This->m_pFilter = pFilter; + if (This->m_pFilter) { + IBaseFilter_AddRef(This->m_pFilter); + } + This->m_cRef = 1; + This->m_nPos = nPos; + *ppv = &This->IEnumPins_iface; + + return S_OK; +} + +/* + * HWCFilter + */ + +typedef struct HWCFilter +{ + IBaseFilter IBaseFilter_iface; + IPin *m_pPin; + IFilterGraph *m_pFilterGraph; + FILTER_STATE m_state; + long m_cRef; +} HWCFilter; + +static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface) +{ + return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface); +} + +static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) +{ + if(IsEqualIID(riid, &IID_IUnknown)) { + *ppv = (IUnknown*)iface; + } else if (IsEqualIID(riid, &IID_IPersist)) { + *ppv = (IPersist*)iface; + } else if (IsEqualIID(riid, &IID_IMediaFilter)) { + *ppv = (IMediaFilter*)iface; + } else if (IsEqualIID(riid, &IID_IBaseFilter)) { + *ppv = (IBaseFilter*)iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IBaseFilter_AddRef(iface); + return S_OK; +} + +static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + return InterlockedIncrement(&This->m_cRef); +} + +static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + if( InterlockedDecrement(&This->m_cRef) == 0) { + if (This->m_pPin) { + IPin_Release(This->m_pPin); + This->m_pPin = NULL; + } + if (This->m_pFilterGraph) { + IFilterGraph_Release(This->m_pFilterGraph); + This->m_pFilterGraph = NULL; + } + g_free((void*)This); + return 0; + } + return This->m_cRef; +} + +static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID) +{ + if (pClsID == NULL) + return E_POINTER; + return E_NOTIMPL; +} + +static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs, FILTER_STATE *State) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + *State = This->m_state; + return S_OK; +} + +static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock) +{ + return S_OK; +} + +static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **pClock) +{ + *pClock = NULL; + return S_OK; +} + +static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + IPin_EndFlush(This->m_pPin); + This->m_state = State_Stopped; + return S_OK; +} + +static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + This->m_state = State_Paused; + return S_OK; +} + +static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + if (This->m_state == State_Stopped){ + HRESULT hr; + hr = IBaseFilter_Pause(iface); + if (FAILED(hr)) { + return hr; + } + } + + This->m_state = State_Running; + return S_OK; +} + +static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum) +{ + if (ppEnum == NULL) + return E_POINTER; + + HWCEnumPins_Construct(iface, 0, ppEnum); + return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK; +} + +static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + if (ppPin == NULL) + return E_POINTER; + + if (memcmp((void*)Id, (void*)HWCPinName, sizeof(HWCPinName))) { + return VFW_E_NOT_FOUND; + } + + if (!This->m_pPin) { + HWCInPin_Construct(iface, &This->m_pPin); + } + *ppPin = This->m_pPin; + + IPin_AddRef(This->m_pPin); + return S_OK; +} + +static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + if (pInfo == NULL) + return E_POINTER; + + memcpy((void*)pInfo->achName, (void*)HWCFilterName, sizeof(HWCFilterName)); + pInfo->pGraph = This->m_pFilterGraph; + if(This->m_pFilterGraph) { + IFilterGraph_AddRef(This->m_pFilterGraph); + } + return S_OK; +} + +static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, + LPCWSTR pName) +{ + HWCFilter *This = impl_from_IBaseFilter(iface); + + This->m_pFilterGraph = pGraph; + if (pGraph) { + IFilterGraph_AddRef(pGraph); + } + return S_OK; +} + +static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR* pVendorInfo) +{ + return E_NOTIMPL; +} + +static IBaseFilterVtbl HWCFilter_Vtbl = +{ + HWCFilter_QueryInterface, + HWCFilter_AddRef, + HWCFilter_Release, + HWCFilter_GetClassID, + HWCFilter_Stop, + HWCFilter_Pause, + HWCFilter_Run, + HWCFilter_GetState, + HWCFilter_SetSyncSource, + HWCFilter_GetSyncSource, + HWCFilter_EnumPins, + HWCFilter_FindPin, + HWCFilter_QueryFilterInfo, + HWCFilter_JoinFilterGraph, + HWCFilter_QueryVendorInfo +}; + +static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv) +{ + HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter)); + + if (!This) { + return E_OUTOFMEMORY; + } + + This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl; + This->m_pFilterGraph = NULL; + This->m_state = State_Stopped; + This->m_cRef = 1; + HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin); + *ppv = &This->IBaseFilter_iface; + + return S_OK; +} + +/********************************************************** + * + * Virtual device implementations + * + **********************************************************/ + + +/* + * Declaration global variables for Win32 COM Interfaces + */ +IGraphBuilder *g_pGB ; +ICaptureGraphBuilder2 *g_pCGB; +IMediaControl *g_pMediaControl; + +IPin *g_pOutputPin; +IPin *g_pInputPin; +IBaseFilter *g_pDstFilter; +IBaseFilter *g_pSrcFilter; + +IGrabCallback *g_pCallback; + +DWORD g_dwFourcc; +LONG g_dwWidth; +LONG g_dwHeight; +REFERENCE_TIME g_dwAvgInterval; + +// V4L2 defines copy from videodev2.h +#define V4L2_CTRL_FLAG_SLIDER 0x0020 + +#define V4L2_CTRL_CLASS_USER 0x00980000 +#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) +#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) +#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) +#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) +#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) + +#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ + +typedef struct tagMaruCamConvertPixfmt { + uint32_t fmt; /* fourcc */ + uint32_t bpp; /* bits per pixel, 0 for compressed formats */ + uint32_t needs_conversion; +} MaruCamConvertPixfmt; + +static MaruCamConvertPixfmt supported_dst_pixfmts[] = { + { V4L2_PIX_FMT_YUYV, 16, 0 }, + { V4L2_PIX_FMT_YUV420, 12, 0 }, + { V4L2_PIX_FMT_YVU420, 12, 0 }, +}; + +typedef struct tagMaruCamConvertFrameInfo { + uint32_t width; + uint32_t height; +} MaruCamConvertFrameInfo; + +static MaruCamConvertFrameInfo supported_dst_frames[] = { + { 640, 480 }, + { 352, 288 }, + { 320, 240 }, + { 176, 144 }, + { 160, 120 }, +}; + +#define MARUCAM_CTRL_VALUE_MAX 20 +#define MARUCAM_CTRL_VALUE_MIN 1 +#define MARUCAM_CTRL_VALUE_MID 10 +#define MARUCAM_CTRL_VALUE_STEP 1 + +struct marucam_qctrl { + uint32_t id; + uint32_t hit; + long min; + long max; + long step; + long init_val; +}; + +static struct marucam_qctrl qctrl_tbl[] = { + { V4L2_CID_BRIGHTNESS, 0, }, + { V4L2_CID_CONTRAST, 0, }, + { V4L2_CID_SATURATION,0, }, + { V4L2_CID_SHARPNESS, 0, }, +}; + +static MaruCamState *g_state = NULL; + +static uint32_t cur_fmt_idx = 0; +static uint32_t cur_frame_idx = 0; + + +/* + * Helper functions - converting image formats, converting values + */ + +void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest, + uint32_t width, uint32_t height, uint32_t yvu); + + +static long value_convert_from_guest(long min, long max, long value) +{ + double rate = 0.0; + long dist = 0, ret = 0; + + dist = max - min; + + if (dist < MARUCAM_CTRL_VALUE_MAX) { + rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; + ret = min + (int32_t)(value / rate); + } else { + rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; + ret = min + (int32_t)(rate * value); + } + return ret; +} + +static long value_convert_to_guest(long min, long max, long value) +{ + double rate = 0.0; + long dist = 0, ret = 0; + + dist = max - min; + + if (dist < MARUCAM_CTRL_VALUE_MAX) { + rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist; + ret = (int32_t)((double)(value - min) * rate); + } else { + rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX; + ret = (int32_t)((double)(value - min) / rate); + } + + return ret; +} + +/* + * Callback function for grab frames + */ +static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer) +{ + static uint32_t index = 0; + static uint32_t is_init = 1; + uint32_t width, height; + width = supported_dst_frames[cur_frame_idx].width; + height = supported_dst_frames[cur_frame_idx].height; + void *buf = g_state->vaddr + (g_state->buf_size * index); + + if (is_init == 1) { + qemu_thread_get_self(&g_state->thread_id); + is_init = 0; + } + + switch (supported_dst_pixfmts[cur_fmt_idx].fmt) { + case V4L2_PIX_FMT_YUV420: + v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1); + break; + case V4L2_PIX_FMT_YUYV: + memcpy(buf, (void*)pBuffer, dwSize); + break; + } + index = !index; + + if (g_state->req_frame) { + qemu_irq_raise(g_state->dev.irq[2]); + g_state->req_frame = 0; + } + return S_OK; +} + +/* + * Internal functions for manipulate interfaces + */ + +static STDMETHODIMP_(void) CloseInterfaces(void) +{ + INFO("%s\n", __func__); + if (g_pMediaControl) + g_pMediaControl->lpVtbl->Stop(g_pMediaControl); + + if (g_pOutputPin) + g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin); + + SAFE_RELEASE(g_pGB); + SAFE_RELEASE(g_pCGB); + SAFE_RELEASE(g_pMediaControl); + SAFE_RELEASE(g_pOutputPin); + SAFE_RELEASE(g_pInputPin); + SAFE_RELEASE(g_pDstFilter); + SAFE_RELEASE(g_pSrcFilter); + SAFE_RELEASE(g_pCallback); +} + +static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt) +{ + INFO("%s\n", __func__); + if (pmt == NULL) { + return; + } + + if (pmt->cbFormat != 0) { + CoTaskMemFree((PVOID)pmt->pbFormat); + pmt->cbFormat = 0; + pmt->pbFormat = NULL; + } + if (pmt->pUnk != NULL) { + pmt->pUnk->lpVtbl->Release(pmt->pUnk); + pmt->pUnk = NULL; + } + + CoTaskMemFree((PVOID)pmt); +} + +static STDMETHODIMP GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) +{ + HRESULT hr; + IEnumPins *pEnum = NULL; + IPin *pPin = NULL; + + INFO("%s\n", __func__); + + if (ppPin == NULL) + { + return E_POINTER; + } + + hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum); + if (FAILED(hr)) + return hr; + + while(pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) + { + PIN_DIRECTION PinDirThis; + hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis); + if (FAILED(hr)) + { + SAFE_RELEASE(pPin); + SAFE_RELEASE(pEnum); + return hr; + } + if (PinDir == PinDirThis) + { + *ppPin = pPin; + SAFE_RELEASE(pEnum); + return S_OK; + } + SAFE_RELEASE(pPin); + } + + SAFE_RELEASE(pEnum); + return S_FALSE; +} + +static STDMETHODIMP GraphBuilder_Init(void) +{ + HRESULT hr; + INFO("%s\n", __func__); + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC, &IID_IGraphBuilder, (void**)&g_pGB); + if (FAILED(hr)) + return hr; + + hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, &IID_ICaptureGraphBuilder2, (void**)&g_pCGB); + if (FAILED(hr)) + return hr; + + hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB); + if (FAILED(hr)) + return hr; + + hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl, (void **)&g_pMediaControl); + if (FAILED(hr)) + return hr; + + hr = HWCGrabCallback_Construct(&g_pCallback); + if (g_pCallback == NULL) + hr = E_OUTOFMEMORY; + + hr = ((HWCGrabCallback*)g_pCallback)->SetCallback(g_pCallback, (CallbackFn)marucam_device_callbackfn); + + return hr; +} + +static STDMETHODIMP BindSourceFilter(void) +{ + HRESULT hr; + ICreateDevEnum *pCreateDevEnum = NULL; + IEnumMoniker *pEnumMK = NULL; + IMoniker *pMoniKer; + + INFO("%s\n", __func__); + hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, &IID_ICreateDevEnum, (void**)&pCreateDevEnum); + if (FAILED(hr)) + return hr; + + hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum, &CLSID_VideoInputDeviceCategory, &pEnumMK, 0); + if (FAILED(hr)) + { + pCreateDevEnum->lpVtbl->Release(pCreateDevEnum); + return hr; + } + + if (!pEnumMK) + { + pCreateDevEnum->lpVtbl->Release(pCreateDevEnum); + return E_FAIL; + } + pEnumMK->lpVtbl->Reset(pEnumMK); + + hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL); + if (hr == S_FALSE) + { + hr = E_FAIL; + } + if (SUCCEEDED(hr)) + { + IPropertyBag *pBag = NULL; + hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0, &IID_IPropertyBag, (void **)&pBag); + if(SUCCEEDED(hr)) + { + VARIANT var; + var.vt = VT_BSTR; + hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL); + if (hr == NOERROR) + { + hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL, &IID_IBaseFilter, (void**)&g_pSrcFilter); + if (FAILED(hr)) + { + ERR("Counldn't bind moniker to filter object!!\n"); + } + else + { + g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter); + } + SysFreeString(var.bstrVal); + } + pBag->lpVtbl->Release(pBag); + } + pMoniKer->lpVtbl->Release(pMoniKer); + } + + if (SUCCEEDED(hr)) + { + hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture"); + if (hr != S_OK && hr != S_FALSE) + { + ERR("Counldn't add Video Capture filter to our graph!\n"); + } + } + + return hr; +} + +static STDMETHODIMP BindTargetFilter(void) +{ + HRESULT hr; + hr = HWCFilter_Construct(&g_pDstFilter); + + INFO("%s\n", __func__); + if (SUCCEEDED(hr) && g_pDstFilter) + { + hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter"); + if (FAILED(hr)) + { + ERR("Counldn't add HWCFilterr to our graph!\n"); + } + } + return hr; +} + +static STDMETHODIMP ConnectFilters(void) +{ + HRESULT hr; + + INFO("%s\n", __func__); + hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin); + if (FAILED(hr)) + return hr; + + hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin); + if (FAILED(hr)) + return hr; + + hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin); + return hr; +} + +static STDMETHODIMP SetDefaultValues(void) +{ + HRESULT hr; + IAMStreamConfig *pSConfig; + int iCount = 0, iSize = 0; + + INFO("%s\n", __func__); + hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0, g_pSrcFilter, &IID_IAMStreamConfig, (void**)&pSConfig); + if (FAILED(hr)) { + ERR("failed to FindInterface method\n"); + return hr; + } + + hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize); + if (FAILED(hr)) + { + ERR("failed to GetNumberOfCapabilities method\n"); + pSConfig->lpVtbl->Release(pSConfig); + return hr; + } + + if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) + { + int iFormat = 0; + for (iFormat = 0; iFormat < iCount; iFormat++) + { + VIDEO_STREAM_CONFIG_CAPS scc; + AM_MEDIA_TYPE *pmtConfig; + + hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig, (BYTE*)&scc); + if (hr == S_OK) + { + if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) + { + VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pmtConfig->pbFormat; + if ((pvi->bmiHeader.biWidth == g_dwWidth) && + (pvi->bmiHeader.biHeight == g_dwHeight) && + (pvi->bmiHeader.biCompression == g_dwFourcc)) + { + pvi->AvgTimePerFrame = g_dwAvgInterval; + hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig); + DeleteMediaType(pmtConfig); + INFO("Setting default values.\n"); + break; + } + } + DeleteMediaType(pmtConfig); + } + } + } + pSConfig->lpVtbl->Release(pSConfig); + return hr; +} + +static STDMETHODIMP SetResolution(LONG width, LONG height) +{ + HRESULT hr; + IAMStreamConfig* vsc = NULL; + AM_MEDIA_TYPE* pmt = NULL; + + INFO("%s\n", __func__); + hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, g_pSrcFilter, &IID_IAMStreamConfig, (void**)&vsc); + if (FAILED(hr)) + return hr; + + hr = vsc->lpVtbl->GetFormat(vsc, &pmt); + if (FAILED(hr)) + { + vsc->lpVtbl->Release(vsc); + return hr; + } + + if (pmt != NULL) + { + if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) + { + VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pmt->pbFormat; + pvi->bmiHeader.biWidth = width; + pvi->bmiHeader.biHeight = height; + pvi->AvgTimePerFrame = g_dwAvgInterval; + pvi->bmiHeader.biSizeImage = ((width * pvi->bmiHeader.biBitCount) >> 3 ) * height; + hr = vsc->lpVtbl->SetFormat(vsc, pmt); + } + DeleteMediaType(pmt); + } + vsc->lpVtbl->Release(vsc); + return hr; +} + +static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax, long *pStep, long *pDefault) +{ + HRESULT hr; + long Flags; + IAMVideoProcAmp *pProcAmp = NULL; + + INFO("%s\n", __func__); + + hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp); + if (FAILED(hr)) { + return hr; + } + + hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax, pStep, pDefault, &Flags); + + SAFE_RELEASE(pProcAmp); + return hr; +} + +static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue) +{ + HRESULT hr; + long Flags; + IAMVideoProcAmp *pProcAmp = NULL; + + INFO("%s\n", __func__); + hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp); + if (FAILED(hr)) + return hr; + + hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags); + if (FAILED(hr)) { + ERR("Failed to get property for video\n"); + } + + SAFE_RELEASE(pProcAmp); + return hr; +} + +static STDMETHODIMP SetVideoProcAmp(long nProperty, long value) +{ + HRESULT hr; + + IAMVideoProcAmp *pProcAmp = NULL; + hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp); + if (FAILED(hr)) + return hr; + + hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value, VideoProcAmp_Flags_Manual); + if (FAILED(hr)) { + ERR("Failed to set property for video\n"); + } + SAFE_RELEASE(pProcAmp); + return hr; +} + +// MARUCAM_CMD_INIT +void marucam_device_init(MaruCamState* state) +{ + g_state = state; +} + +// MARUCAM_CMD_OPEN +void marucam_device_open(MaruCamState* state) +{ + HRESULT hr; + MaruCamParam *param = state->param; + param->top = 0; + + INFO("%s\n", __func__); + CoInitialize(NULL); + + hr = GraphBuilder_Init(); + if (FAILED(hr)) { + ERR("GraphBuilder_Init\n"); + goto error_failed; + } + + hr = BindSourceFilter(); + if (FAILED(hr)) { + ERR("BindSourceFilter\n"); + goto error_failed; + } + + hr = BindTargetFilter(); + if (FAILED(hr)) { + ERR("BindTargetFilter\n"); + goto error_failed; + } + + hr = ConnectFilters(); + if (FAILED(hr)) { + ERR("ConnectFilters\n"); + goto error_failed; + } + + g_dwAvgInterval = 333333; + g_dwFourcc = MAKEFOURCC('Y','U','Y','2'); + g_dwHeight = 480; + g_dwWidth = 640; + hr = SetDefaultValues(); + if (hr != S_OK) { + ERR("SetDefaultValues\n"); + goto error_failed; + } + + INFO("Open successfully!!!\n"); + return; + +error_failed: + CloseInterfaces(); + CoUninitialize(); + param->errCode = EINVAL; + ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr); +} + +// MARUCAM_CMD_CLOSE +void marucam_device_close(MaruCamState* state) +{ + MaruCamParam *param = state->param; + param->top = 0; + + CloseInterfaces(); + CoUninitialize(); + INFO("Close successfully!!!\n"); +} + +// MARUCAM_CMD_START_PREVIEW +void marucam_device_start_preview(MaruCamState* state) +{ + HRESULT hr; + uint32_t width, height; + MaruCamParam *param = state->param; + param->top = 0; + + INFO("%s\n", __func__); + assert(g_pCallback != NULL); + hr = ((HWCInPin*)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, g_pCallback); + if (FAILED(hr)) { + ERR("Failed to set IGrabCallback interface.\n"); + param->errCode = EINVAL; + return; + } + + hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl); + if (FAILED(hr)) { + ERR("Failed to run media control.\n"); + param->errCode = EINVAL; + return; + } + + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 1; + qemu_mutex_unlock(&state->thread_mutex); + + width = supported_dst_frames[cur_frame_idx].width; + height = supported_dst_frames[cur_frame_idx].height; + state->buf_size = height * ((width * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3); + + INFO("Start preview!!!\n"); +} + +// MARUCAM_CMD_STOP_PREVIEW +void marucam_device_stop_preview(MaruCamState* state) +{ + HRESULT hr; + MaruCamParam *param = state->param; + param->top = 0; + + hr = ((HWCInPin*)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL); + if (FAILED(hr)) { + ERR("Failed to set IGrabCallback interface.\n"); + param->errCode = EINVAL; + return; + } + + hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl); + if (FAILED(hr)) { + ERR("Failed to stop media control.\n"); + param->errCode = EINVAL; + return; + } + + qemu_mutex_lock(&state->thread_mutex); + state->streamon = 0; + qemu_mutex_unlock(&state->thread_mutex); + state->buf_size = 0; + + INFO("Stop preview!!!\n"); +} + +// MARUCAM_CMD_S_PARAM +void marucam_device_s_param(MaruCamState* state) +{ + MaruCamParam *param = state->param; + + param->top = 0; + TRACE("setting fps : %d/%d\n", param->stack[0], param->stack[1]); +} + +// MARUCAM_CMD_G_PARAM +void marucam_device_g_param(MaruCamState* state) +{ + MaruCamParam *param = state->param; + + param->top = 0; + TRACE("getting fps : 30/1\n"); + + param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME + param->stack[1] = 1; // numerator; + param->stack[2] = 30; // denominator; +} + +// MARUCAM_CMD_S_FMT +void marucam_device_s_fmt(MaruCamState* state) +{ + uint32_t width, height, pixfmt, pidx, fidx; + MaruCamParam *param = state->param; + + param->top = 0; + width = param->stack[0]; // width + height = param->stack[1]; // height + pixfmt = param->stack[2]; // pixelformat + + for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) { + if ((supported_dst_frames[fidx].width == width) && + (supported_dst_frames[fidx].height == height)) { + break; + } + } + if (fidx == ARRAY_SIZE(supported_dst_frames)) { + param->errCode = EINVAL; + return; + } + for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) { + if (supported_dst_pixfmts[pidx].fmt == pixfmt) { + break; + } + } + if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) { + param->errCode = EINVAL; + return; + } + + if ((supported_dst_frames[cur_frame_idx].width != width) && + (supported_dst_frames[cur_frame_idx].height != height)) { + HRESULT hr = SetResolution((LONG)width, (LONG)height); + if (FAILED(hr)) { + param->errCode = EINVAL; + return; + } + g_dwWidth = (LONG)width; + g_dwHeight = (LONG)height; + } + + param->stack[0] = width; + param->stack[1] = height; + param->stack[2] = 1; // V4L2_FIELD_NONE + param->stack[3] = pixfmt; + // bytes per line = (width * bpp) / 8 + param->stack[4] = (width * supported_dst_pixfmts[pidx].bpp) >> 3; + param->stack[5] = param->stack[4] * height; // height * bytesperline + param->stack[6] = 0; + param->stack[7] = 0; + + cur_frame_idx = fidx; + cur_fmt_idx = pidx; + + TRACE("Set format...\n"); +} + +// MARUCAM_CMD_G_FMT +void marucam_device_g_fmt(MaruCamState* state) +{ + MaruCamParam *param = state->param; + + param->top = 0; + + param->stack[0] = supported_dst_frames[cur_frame_idx].width; // width + param->stack[1] = supported_dst_frames[cur_frame_idx].height; // height + param->stack[2] = 1; // V4L2_FIELD_NONE + param->stack[3] = supported_dst_pixfmts[cur_fmt_idx].fmt; // pixelformat + // bytes per line = (width * bpp) / 8 + param->stack[4] = (param->stack[0] * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3; + param->stack[5] = param->stack[1] * param->stack[4]; // height * bytesperline + param->stack[6] = 0; + param->stack[7] = 0; + + TRACE("Get format...\n"); +} + +void marucam_device_try_fmt(MaruCamState* state) +{ + uint32_t width, height, pixfmt, i; + MaruCamParam *param = state->param; + + param->top = 0; + width = param->stack[0]; // width + height = param->stack[1]; // height + pixfmt = param->stack[2]; // pixelformat + + for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) { + if ((supported_dst_frames[i].width == width) && + (supported_dst_frames[i].height == height)) { + break; + } + } + if (i == ARRAY_SIZE(supported_dst_frames)) { + param->errCode = EINVAL; + return; + } + for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) { + if (supported_dst_pixfmts[i].fmt == pixfmt) { + break; + } + } + if (i == ARRAY_SIZE(supported_dst_pixfmts)) { + param->errCode = EINVAL; + return; + } + + param->stack[0] = width; + param->stack[1] = height; + param->stack[2] = 1; // V4L2_FIELD_NONE + param->stack[3] = pixfmt; + // bytes per line = (width * bpp) / 8 + param->stack[4] = (width * supported_dst_pixfmts[i].bpp) >> 3; + param->stack[5] = param->stack[4] * height; // height * bytesperline + param->stack[6] = 0; + param->stack[7] = 0; +} + +void marucam_device_enum_fmt(MaruCamState* state) +{ + uint32_t index; + MaruCamParam *param = state->param; + + param->top = 0; + index = param->stack[0]; + + if (index >= ARRAY_SIZE(supported_dst_pixfmts)) { + param->errCode = EINVAL; + return; + } + param->stack[1] = 0; // flags = NONE; + param->stack[2] = supported_dst_pixfmts[index].fmt; // pixelformat; + /* set description */ + switch (supported_dst_pixfmts[index].fmt) { + case V4L2_PIX_FMT_YUYV: + memcpy(¶m->stack[3], "YUY2", 32); + break; + case V4L2_PIX_FMT_YUV420: + memcpy(¶m->stack[3], "YU12", 32); + break; + case V4L2_PIX_FMT_YVU420: + memcpy(¶m->stack[3], "YV12", 32); + break; + } +} + +void marucam_device_qctrl(MaruCamState* state) +{ + HRESULT hr; + uint32_t id, i; + long property, min, max, step, def_val, set_val; + char name[32] = {0,}; + MaruCamParam *param = state->param; + + param->top = 0; + id = param->stack[0]; + + switch (id) { + case V4L2_CID_BRIGHTNESS: + TRACE("V4L2_CID_BRIGHTNESS\n"); + property = VideoProcAmp_Brightness; + memcpy((void*)name, (void*)"brightness", 32); + i = 0; + break; + case V4L2_CID_CONTRAST: + TRACE("V4L2_CID_CONTRAST\n"); + property = VideoProcAmp_Contrast; + memcpy((void*)name, (void*)"contrast", 32); + i = 1; + break; + case V4L2_CID_SATURATION: + TRACE("V4L2_CID_SATURATION\n"); + property = VideoProcAmp_Saturation; + memcpy((void*)name, (void*)"saturation", 32); + i = 2; + break; + case V4L2_CID_SHARPNESS: + TRACE("V4L2_CID_SHARPNESS\n"); + property = VideoProcAmp_Sharpness; + memcpy((void*)name, (void*)"sharpness", 32); + i = 3; + break; + default: + param->errCode = EINVAL; + return; + } + hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val); + if (FAILED(hr)) { + param->errCode = EINVAL; + ERR("failed to query video controls [HRESULT : 0x%x]\n", hr); + return; + } else { + qctrl_tbl[i].hit = 1; + qctrl_tbl[i].min = min; + qctrl_tbl[i].max = max; + qctrl_tbl[i].step = step; + qctrl_tbl[i].init_val = def_val; + + if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) { + set_val = 0; + } else { + set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2; + } + hr = SetVideoProcAmp(property, set_val); + if (FAILED(hr)) { + param->errCode = EINVAL; + ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr); + return; + } + } + + param->stack[0] = id; + param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum + param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum + param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step + param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value + param->stack[5] = V4L2_CTRL_FLAG_SLIDER; + /* name field setting */ + memcpy(¶m->stack[6], (void*)name, sizeof(name)/sizeof(name[0])); +} + +void marucam_device_s_ctrl(MaruCamState* state) +{ + HRESULT hr; + uint32_t i; + long property, set_val; + MaruCamParam *param = state->param; + + param->top = 0; + + switch (param->stack[0]) { + case V4L2_CID_BRIGHTNESS: + i = 0; + property = VideoProcAmp_Brightness; + break; + case V4L2_CID_CONTRAST: + i = 1; + property = VideoProcAmp_Contrast; + break; + case V4L2_CID_SATURATION: + i = 2; + property = VideoProcAmp_Saturation; + break; + case V4L2_CID_SHARPNESS: + i = 3; + property = VideoProcAmp_Sharpness; + break; + default: + param->errCode = EINVAL; + return; + } + set_val = value_convert_from_guest(qctrl_tbl[i].min, + qctrl_tbl[i].max, (long)param->stack[1]); + hr = SetVideoProcAmp(property, set_val); + if (FAILED(hr)) { + param->errCode = EINVAL; + ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr); + return; + } +} + +void marucam_device_g_ctrl(MaruCamState* state) +{ + HRESULT hr; + uint32_t i; + long property, get_val; + MaruCamParam *param = state->param; + + param->top = 0; + switch (param->stack[0]) { + case V4L2_CID_BRIGHTNESS: + i = 0; + property = VideoProcAmp_Brightness; + break; + case V4L2_CID_CONTRAST: + i = 1; + property = VideoProcAmp_Contrast; + break; + case V4L2_CID_SATURATION: + i = 2; + property = VideoProcAmp_Saturation; + break; + case V4L2_CID_SHARPNESS: + i = 3; + property = VideoProcAmp_Sharpness; + break; + default: + param->errCode = EINVAL; + return; + } + + hr = GetVideoProcAmp(property, &get_val); + if (FAILED(hr)) { + param->errCode = EINVAL; + ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr); + return; + } + param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min, + qctrl_tbl[i].max, get_val); +} + +void marucam_device_enum_fsizes(MaruCamState* state) +{ + uint32_t index, pixfmt, i; + MaruCamParam *param = state->param; + + param->top = 0; + index = param->stack[0]; + pixfmt = param->stack[1]; + + if (index >= ARRAY_SIZE(supported_dst_frames)) { + param->errCode = EINVAL; + return; + } + for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) { + if (supported_dst_pixfmts[i].fmt == pixfmt) + break; + } + + if (i == ARRAY_SIZE(supported_dst_pixfmts)) { + param->errCode = EINVAL; + return; + } + + param->stack[0] = supported_dst_frames[index].width; + param->stack[1] = supported_dst_frames[index].height; +} + +void marucam_device_enum_fintv(MaruCamState* state) +{ + MaruCamParam *param = state->param; + + param->top = 0; + + // switch by index(param->stack[0]) + switch (param->stack[0]) { + case 0: + param->stack[1] = 30; // denominator + break; + default: + param->errCode = EINVAL; + return; + } + param->stack[0] = 1; // numerator +} + +void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest, + uint32_t width, uint32_t height, uint32_t yvu) +{ + uint32_t i, j; + const unsigned char *src1; + unsigned char *udest, *vdest; + + /* copy the Y values */ + src1 = src; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j += 2) { + *dest++ = src1[0]; + *dest++ = src1[2]; + src1 += 4; + } + } + + /* copy the U and V values */ + src++; /* point to V */ + src1 = src + width * 2; /* next line */ + if (yvu) { + vdest = dest; + udest = dest + width * height / 4; + } else { + udest = dest; + vdest = dest + width * height / 4; + } + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + *udest++ = ((int) src[0] + src1[0]) / 2; /* U */ + *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */ + src += 4; + src1 += 4; + } + src = src1; + src1 += width * 2; + } +} -- 2.34.1