From: jinhyung.jo Date: Wed, 8 Jul 2015 13:03:19 +0000 (+0900) Subject: maru-camera: Implemented a virtual camera X-Git-Tag: Tizen_Studio_1.3_Release_p2.3.2~310 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2c5c3dc0a1ce466ce7b0576d1029f57ed2943c0f;p=sdk%2Femulator%2Fqemu.git maru-camera: Implemented a virtual camera It implemented using a Qt library. And it supports image files that QImage can support by qt plugin. It displays each image every a 100ms. Also implemented simple feature that displays solid color image for SWT UI without Qt. Change-Id: Ida76b5c5ab6bda17ee2bfc2414c24d1e308ef4c5 Signed-off-by: Jinhyung Jo --- diff --git a/tizen/src/hw/pci/Makefile.objs b/tizen/src/hw/pci/Makefile.objs index 7b58c9789c..8318d52b80 100644 --- a/tizen/src/hw/pci/Makefile.objs +++ b/tizen/src/hw/pci/Makefile.objs @@ -10,17 +10,24 @@ endif obj-y += maru_brightness.o -obj-y += maru_camera.o +obj-y += maru_camera.o maru_camera_convert.o +obj-y += maru_camera_virtual.o +ifdef CONFIG_QT +obj-y += maru_camera_qtimage.o +$(obj)/maru_camera_qtimage.o: QEMU_CFLAGS += $(QT_CFLAGS) +else +obj-y += maru_camera_swimage.o +endif ifdef CONFIG_LINUX obj-y += maru_camera_linux.o LIBS += -lv4l2 -lv4lconvert endif ifdef CONFIG_WIN32 -obj-y += maru_camera_win32.o maru_camera_convert.o +obj-y += maru_camera_win32.o LIBS += -lole32 -loleaut32 -luuid -lstrmiids endif ifdef CONFIG_DARWIN -obj-y += maru_camera_darwin.o maru_camera_convert.o +obj-y += maru_camera_darwin.o LIBS += -framework Foundation -framework SystemConfiguration LIBS += -framework Cocoa -framework QTKit -framework CoreVideo LIBS += -framework AppKit diff --git a/tizen/src/hw/pci/maru_camera.c b/tizen/src/hw/pci/maru_camera.c index d0fa1a423f..72e6f4fb54 100644 --- a/tizen/src/hw/pci/maru_camera.c +++ b/tizen/src/hw/pci/maru_camera.c @@ -48,7 +48,7 @@ MULTI_DEBUG_CHANNEL(tizen, camera); #define MARU_PCI_CAMERA_DEVICE_NAME "maru-camera" /* PCI region size must be pow2. */ -/* set to 1048(2^10) * 1048(2^10) * 4(2^2) = 4,194,304(2^22) */ +/* set to 1024(2^10) * 1024(2^10) * 4(2^2) = 4,194,304(2^22) */ #define MARUCAM_MEM_SIZE (1 << 22) #define MARUCAM_REG_SIZE (1 << 8) /* 64 * 4Byte = 256(2^8) */ /* RAM type region must be at least 4KB */ @@ -64,6 +64,11 @@ marucam_mmio_read(void *opaque, hwaddr offset) MaruCamState *state = (MaruCamState *)opaque; switch (offset & 0xFF) { + /* Passes the index into the kernel driver */ + case MARUCAM_CMD_INIT: + ret = state->index; + break; + /* return isr value and clear the interrupt signal */ case MARUCAM_CMD_ISR: qemu_mutex_lock(&state->thread_mutex); ret = state->isr; @@ -211,18 +216,38 @@ static int marucam_initfn(PCIDevice *dev) { MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev); uint8_t *pci_conf = s->dev.config; - - /* Check available webcam - * If there is not one, you can't use the camera. - */ - if (!marucam_device_check()) { - s->initialized = false; - INFO("Failed to check the camera device, " - "You can *not* use the camera\n"); + static bool is_used_index[2]; + static bool has_native; + + /* If there is no index property in 'maru-camera' option, + it gives an index by the following routine. */ + TRACE("[%s] Input index(%d), path(%s)\n", __func__, + s->index, s->path ? s->path : NULL); + if (s->index == 0xFF) { + if (!is_used_index[0]) { + s->index = 0; + is_used_index[s->index] = true; + } else if (!is_used_index[1]) { + s->index = 1; + is_used_index[s->index] = true; + } else { + WARN("No more available, there are already 2 instances\n"); + return 0; + } + } else if (s->index == 0 || s->index == 1) { + if (is_used_index[s->index]) { + WARN("Input index(%u) is already in use\n", s->index); + return 0; + } else { + is_used_index[s->index] = true; + } + } else { + WARN("Input index(%u) is out of range[0~1]\n", s->index); return 0; } - pci_config_set_interrupt_pin(pci_conf, 0x03); + /* Modify the pin number to avoid interrupt conflicts */ + pci_config_set_interrupt_pin(pci_conf, (0x03 - s->index)); memory_region_init_ram(&s->fbmem, OBJECT(s), "marucamera.fbmem", MARUCAM_MEM_SIZE, &error_abort); @@ -244,15 +269,31 @@ static int marucam_initfn(PCIDevice *dev) pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->iomem); pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ioreg); - /* for worker thread */ - qemu_cond_init(&s->thread_cond); - qemu_mutex_init(&s->thread_mutex); + /* Check available webcam + * If there is not one, you can use the virtual camera. + */ + if (s->path || has_native || !marucam_device_check()) { + INFO("[cam%d] Virtual Camera mode\n", s->index); + s->backend = marucam_virtual_backend_create(s); + } else { + INFO("[cam%d] Native Camera mode\n", s->index); + s->backend = marucam_native_backend_create(s); + has_native = true; + } - s->backend = marucam_backend_create(s); - s->backend->init(s); + if (s->backend) { + /* for worker thread */ + qemu_cond_init(&s->thread_cond); + qemu_mutex_init(&s->thread_mutex); - s->tx_bh = qemu_bh_new(marucam_tx_bh, s); - INFO("initialize maru-camera device\n"); + s->backend->init(s); + + s->tx_bh = qemu_bh_new(marucam_tx_bh, s); + INFO("initialize the maru-camera%d device\n", s->index); + } else { + s->initialized = false; + ERR("failed to initialize the maru-camera%d device\n", s->index); + } return 0; } @@ -271,7 +312,7 @@ static void marucam_exitfn(PCIDevice *pci_dev) qemu_mutex_destroy(&s->thread_mutex); } - INFO("finalize maru-camera device\n"); + INFO("finalize maru-camera%d device\n", s->index); } static void marucam_resetfn(DeviceState *d) @@ -285,7 +326,7 @@ static void marucam_resetfn(DeviceState *d) qemu_mutex_unlock(&s->thread_mutex); memset(s->fb_ptr, 0, MARUCAM_MEM_SIZE); memset(s->io_ptr, 0, MARUCAM_IOMEM_SIZE); - INFO("reset maru-camera device\n"); + INFO("reset maru-camera%d device\n", s->index); } } @@ -295,6 +336,12 @@ int maru_camera_pci_init(PCIBus *bus) return 0; } +static Property marucam_props[] = { + DEFINE_PROP_UINT8("index", MaruCamState, index, 0xFF), + DEFINE_PROP_STRING("path", MaruCamState, path), + DEFINE_PROP_END_OF_LIST(), +}; + static void maru_camera_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -306,6 +353,7 @@ static void maru_camera_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA; k->class_id = PCI_CLASS_OTHERS; dc->reset = marucam_resetfn; + dc->props = marucam_props; dc->desc = "MARU Virtual Camera device for Tizen emulator"; } diff --git a/tizen/src/hw/pci/maru_camera.h b/tizen/src/hw/pci/maru_camera.h index 06035224d3..4266b1468b 100644 --- a/tizen/src/hw/pci/maru_camera.h +++ b/tizen/src/hw/pci/maru_camera.h @@ -113,6 +113,10 @@ struct MaruCamState { uint32_t req_frame; uint32_t ret_val; + /* Properties */ + uint8_t index; /* device index (0 or 1)*/ + char *path; /* image file path */ + MemoryRegion fbmem; MemoryRegion iomem; MemoryRegion ioreg; @@ -120,7 +124,8 @@ struct MaruCamState { MaruCamBackend *backend; }; -MaruCamBackend *marucam_backend_create(MaruCamState *state); +MaruCamBackend *marucam_native_backend_create(MaruCamState *state); +MaruCamBackend *marucam_virtual_backend_create(MaruCamState *state); int marucam_device_check(void); diff --git a/tizen/src/hw/pci/maru_camera_darwin.m b/tizen/src/hw/pci/maru_camera_darwin.m index e3031a2a95..39cdba1b17 100644 --- a/tizen/src/hw/pci/maru_camera_darwin.m +++ b/tizen/src/hw/pci/maru_camera_darwin.m @@ -541,9 +541,8 @@ static void backend_mac_close(MaruCamState *state) if (backend->driver != nil) { [backend->driver dealloc]; backend->driver = nil; + INFO("Closed\n"); } - - INFO("Closed\n"); } static void backend_mac_stream_on(MaruCamState *state) @@ -880,7 +879,7 @@ static void backend_mac_enum_fintv(MaruCamState *state) } } -MaruCamBackend *marucam_backend_create(MaruCamState *state) +MaruCamBackend *marucam_native_backend_create(MaruCamState *state) { MCBackendMac *backend_mac; diff --git a/tizen/src/hw/pci/maru_camera_image.h b/tizen/src/hw/pci/maru_camera_image.h new file mode 100644 index 0000000000..5e3c1f98c4 --- /dev/null +++ b/tizen/src/hw/pci/maru_camera_image.h @@ -0,0 +1,54 @@ +/* + * Qt5 module for the virtual camera + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung Jo + * Sangho Park + * + * 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 + * + * with Qt5 QImage class + */ + +#ifndef __MARU_CAMERA_IMAGE_H__ +#define __MARU_CAMERA_IMAGE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +void *imagemgr_create(void *parent); +int imagemgr_init(void *mgr, const char *path); +void imagemgr_reset(void *mgr); +void imagemgr_release(void *mgr); +void imagemgr_prepare(void *mgr); +bool imagemgr_is_init(void *mgr); + +void imagemgr_set_resolution(void *mgr, int w, int h); +void *imagemgr_get_data(void *mgr); +void imagemgr_adjust_ctrl(void *mgr, + unsigned int ctrl_id, + int ctrl_value); +#ifdef __cplusplus +} +#endif + +#endif /* __MARU_CAMERA_IMAGE_H__ */ + diff --git a/tizen/src/hw/pci/maru_camera_linux.c b/tizen/src/hw/pci/maru_camera_linux.c index 51f2a2edb0..d8677f3c2e 100644 --- a/tizen/src/hw/pci/maru_camera_linux.c +++ b/tizen/src/hw/pci/maru_camera_linux.c @@ -1367,7 +1367,7 @@ static void backend_v4l2_enum_fintv(MaruCamState *state) } } -MaruCamBackend *marucam_backend_create(MaruCamState *state) +MaruCamBackend *marucam_native_backend_create(MaruCamState *state) { MCBackendV4l2 *backend_v4l2; diff --git a/tizen/src/hw/pci/maru_camera_qtimage.cpp b/tizen/src/hw/pci/maru_camera_qtimage.cpp new file mode 100644 index 0000000000..546bee71d6 --- /dev/null +++ b/tizen/src/hw/pci/maru_camera_qtimage.cpp @@ -0,0 +1,502 @@ +/* + * Qt5 module for the virtual camera + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung Jo + * Sangho Park + * + * 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 + * + * with Qt5 QImage class + */ + +#include +#include +#include +#include "maru_camera_image.h" +#include "ui/qemu-pixman.h" + +// Internal classes +// TODO: Add debug info and logs + +// video test colors +enum pim_color { + COLOR_WHITE = 0, + COLOR_YELLOW, + COLOR_CYAN, + COLOR_GREEN, + COLOR_MAGENTA, + COLOR_RED, + COLOR_BLUE, + COLOR_BLACK, + COLOR_GRAY19, + COLOR_GRAY7, + COLOR_MAX +}; + +static const pixman_color_t colors[] = { + // WHITE + { .red = 0xFF << 8, + .green = 0xFF << 8, + .blue = 0xFF << 8, + .alpha = 0 }, + // YELLOW + { .red = 0xFF << 8, + .green = 0xFF << 8, + .blue = 0, + .alpha = 0 }, + // CYAN + { .red = 0, + .green = 0xFF << 8, + .blue = 0xFF << 8, + .alpha = 0 }, + // GREEN + { .red = 0, + .green = 0xFF << 8, + .blue = 0, + .alpha = 0 }, + // MAGENTA + { .red = 0xFF << 8, + .green = 0, + .blue = 0xFF << 8, + .alpha = 0 }, + // RED + { .red = 0xFF << 8, + .green = 0, + .blue = 0, + .alpha = 0 }, + // BLUE + { .red = 0, + .green = 0, + .blue = 0xFF << 8, + .alpha = 0 }, + // BLACK + { .red = 0, + .green = 0, + .blue = 0, + .alpha = 0 }, + // GRAY (#202020) + { .red = 0x20 << 8, + .green = 0x20 << 8, + .blue = 0x20 << 8, + .alpha = 0 }, + // GREY (#505050) + { .red = 0x50 << 8, + .green = 0x50 << 8, + .blue = 0x50 << 8, + .alpha = 0 }, +}; + +class PixmanImageManager +{ +public: + explicit PixmanImageManager(); + ~PixmanImageManager(); + + void makeImages(int w, int h); + void *getImageData(); + +private: + int width; + int height; + int idx; + static const int MAX_DST_IMAGES = 3; + pixman_image_t *dstImages[MAX_DST_IMAGES]; + pixman_image_t *srcImages[COLOR_MAX]; +}; + +PixmanImageManager::PixmanImageManager() +{ + this->width = 0; + this->height = 0; + this->idx = 0; + + for (int i = 0; i < COLOR_MAX; i++) { + srcImages[i] = pixman_image_create_solid_fill(&colors[i]); + } + for (int i = 0; i < MAX_DST_IMAGES; i++) { + dstImages[i] = NULL; + } +} + +PixmanImageManager::~PixmanImageManager() +{ + for (int i = 0; i < COLOR_MAX; i++) { + pixman_image_unref(srcImages[i]); + srcImages[i] = NULL; + } + for (int i = 0; i < MAX_DST_IMAGES; i++) { + pixman_image_unref(dstImages[i]); + dstImages[i] = NULL; + } +} + +void PixmanImageManager::makeImages(int w, int h) +{ + if (w == this->width && h == this->height) { + return; + } else { + this->width = w; + this->height = h; + } + + for (int i = 0; i < MAX_DST_IMAGES; i++) { + if (this->dstImages[i]) { + pixman_image_unref(this->dstImages[i]); + } + this->dstImages[i] = pixman_image_create_bits(PIXMAN_r8g8b8, + w, h, NULL, w * 3); + int h1 = 3 * h / 4; + for (int j = 0; j < COLOR_MAX; j++) { + int x1 = j * w / 7; + int x2 = (j + 1) * w / 7; + pixman_image_composite(PIXMAN_OP_SRC, + this->srcImages[j], + NULL, this->dstImages[i], + 0, 0, 0, 0, x1, 0, (x2 - x1), h1); + } + for (int j = 0; j < COLOR_MAX - COLOR_BLACK; j++) { + int x1 = j * w / 3; + int x2 = (j + 1) * w / 3; + int k = (i + j) % 3; + pixman_image_composite(PIXMAN_OP_SRC, + this->srcImages[COLOR_BLACK + k], + NULL, this->dstImages[i], + 0, 0, 0, 0, x1, h1, (x2 - x1), (h - h1)); + } + } +} + +void *PixmanImageManager::getImageData() +{ + void *buf = pixman_image_get_data(this->dstImages[this->idx++]); + if (this->idx == MAX_DST_IMAGES) { + this->idx = 0; + } + + return buf; +} + +class VCImageManager +{ +public: + explicit VCImageManager(void *parent); + ~VCImageManager(); + + int init(const char *inPath); + void loadImages(); + int findAnimatedImage(); + void loadAnimatedImage(int idx); + void makeConvertedData(int w, int h); + void *getImageData(); + bool isAvail(); + +private: + void *parent; + + int width; + int height; + int idxOfCurData; + + bool isInit; + bool usePixman; + bool loadDone; + + QList *fileList; + QList *imageList; + QList *dataList; + + void createPixmanImageManager(); + PixmanImageManager *pim; +}; + +VCImageManager::VCImageManager(void *parent) +{ + this->parent = parent; + this->width = 0; + this->height = 0; + this->idxOfCurData = 0; + + this->isInit = false; + this->usePixman = false; + this->loadDone = false; + + this->fileList = new QList; + this->imageList = new QList; + this->dataList = new QList; + this->pim = NULL; +} + +VCImageManager::~VCImageManager() +{ + if (this->imageList) { + this->imageList->clear(); + delete this->imageList; + this->imageList = NULL; + } + if (this->fileList) { + this->fileList->clear(); + delete this->fileList; + this->fileList = NULL; + } + if (this->dataList) { + for (int i = 0; i < this->dataList->count(); i++) { + delete this->dataList->at(i); + } + this->dataList->clear(); + delete this->dataList; + this->dataList = NULL; + } +} + +int VCImageManager::init(const char *inPath) +{ + if (inPath) { + // If the inPath is enclosed with double quotes, remove them. + QFileInfo fi(QString(inPath).remove(QChar('\"'))); + QString canonFilePath = fi.canonicalFilePath(); + // single image file + if (fi.exists() && fi.isFile()) { + QImageReader ir(canonFilePath); + if (ir.canRead() && ir.imageCount() > 1) { + this->fileList->append(QDir::cleanPath(canonFilePath)); + } else { // not animated, use generator + createPixmanImageManager(); + } + // directory + } else if (fi.exists() && fi.isDir()) { + QDirIterator it(QDir::cleanPath(canonFilePath), QDir::Files); + if (!it.hasNext()) { // there is no file + createPixmanImageManager(); + } else { + do { + it.next(); + if (!it.fileName().isEmpty()) { + QByteArray format = + QImageReader::imageFormat(it.filePath()); + // QImageReader wrong recognizing the file format + // some file what is compressed by the gzip + // so ignore it + if (!format.isEmpty() && !format.startsWith("svgz")) { + this->fileList->append(it.filePath()); + } + } + } while (it.hasNext()); + if (this->fileList->isEmpty()) { + // there is no image file + // use generator + createPixmanImageManager(); + } + } + } else { + createPixmanImageManager(); + } + } else { + createPixmanImageManager(); + } + + this->isInit = true; + + return 1; +} + +int VCImageManager::findAnimatedImage() +{ + if (this->usePixman) { + return -1; + } + + for (int i = 0; i < this->fileList->count(); i++) { + QImageReader ir(this->fileList->at(i)); + if (ir.canRead() && ir.imageCount() > 1) { + return i; + } + } + return -1; +} + +void VCImageManager::loadAnimatedImage(int idx) +{ + if (this->loadDone || this->usePixman) { + return; + } + + QImageReader ir(this->fileList->at(idx)); + while (ir.canRead()) { + this->imageList->append(ir.read()); + } + this->loadDone = true; +} + +void VCImageManager::loadImages() +{ + if (this->loadDone) { + return; + } + + if (this->usePixman) { + this->loadDone = true; + return; + } + + for (int i = 0; i < this->fileList->count(); i++) { + QImage loadedImage = QImage(this->fileList->at(i)); + if (!loadedImage.isNull()) { + this->imageList->append(loadedImage); + } + } + this->loadDone = true; +} + +void VCImageManager::makeConvertedData(int w, int h) +{ + if (!isAvail()) { + return; + } + + if (w == this->width && h == this->height) { + return; + } else { + this->width = w; + this->height = h; + } + if (this->usePixman) { + this->pim->makeImages(w, h); + } else { + bool dstListIsEmpty = this->dataList->empty(); + for (int i = 0; i < this->imageList->count(); i++) { + QImage img = this->imageList->at(i).rgbSwapped(); + img = img.scaled(this->width, + this->height, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + img = img.convertToFormat(QImage::Format_RGB888); + + if (dstListIsEmpty) { + this->dataList->append(new QByteArray((char *)img.bits(), + img.byteCount())); + } else { + delete this->dataList->at(i); + this->dataList->replace(i, new QByteArray((char *)img.bits(), + img.byteCount())); + } + } + } +} + +void *VCImageManager::getImageData() +{ + if (!isAvail()) { + return NULL; + } + if (usePixman) { + return this->pim->getImageData(); + } else { + QByteArray *ba = this->dataList->at(this->idxOfCurData++); + if (this->idxOfCurData == this->dataList->count()) { + this->idxOfCurData = 0; + } + return reinterpret_cast(ba->data()); + } +} + +bool VCImageManager::isAvail() +{ + return this->isInit; +} + +void VCImageManager::createPixmanImageManager() +{ + if (this->pim) { + return; + } + pim = new PixmanImageManager(); + this->usePixman = true; +} + +// Extern Functions +void *imagemgr_create(void *parent) +{ + VCImageManager *mgr = new VCImageManager(parent); + + return static_cast(mgr); +} + +int imagemgr_init(void *mgr, const char *inPath) +{ + VCImageManager *imagemgr = static_cast(mgr); + + return imagemgr->init(inPath); +} + +void imagemgr_reset(void *mgr) +{ +} + +void imagemgr_release(void *mgr) +{ + VCImageManager *imagemgr = static_cast(mgr); + + delete imagemgr; +} + +void imagemgr_prepare(void *mgr) +{ + + VCImageManager *imagemgr = static_cast(mgr); + + if (!imagemgr->isAvail()) { + return; + } + + int aniIdx = imagemgr->findAnimatedImage(); + if (aniIdx < 0) { + imagemgr->loadImages(); + } else { + imagemgr->loadAnimatedImage(aniIdx); + } +} + +bool imagemgr_is_init(void *mgr) +{ + VCImageManager *imagemgr = static_cast(mgr); + + return imagemgr->isAvail(); +} + +void imagemgr_set_resolution(void *mgr, int w, int h) +{ + VCImageManager *imagemgr = static_cast(mgr); + imagemgr->makeConvertedData(w, h); +} + +void *imagemgr_get_data(void *mgr) +{ + VCImageManager *imagemgr = static_cast(mgr); + + return imagemgr->getImageData(); +} + +void imagemgr_adjust_ctrl(void *mgr, + unsigned int ctrl_id, + int ctrl_value) +{ +} diff --git a/tizen/src/hw/pci/maru_camera_swimage.c b/tizen/src/hw/pci/maru_camera_swimage.c new file mode 100644 index 0000000000..0f8704058c --- /dev/null +++ b/tizen/src/hw/pci/maru_camera_swimage.c @@ -0,0 +1,173 @@ +/* + * Qt5 module for the virtual camera + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung Jo + * Sangho Park + * + * 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 + * + * with Qt5 QImage class + */ + +#include "qemu-common.h" +#include "ui/qemu-pixman.h" +#include "maru_camera_image.h" + +#define VCSWIMAGE_MAX_BUF 20 + +typedef struct VCSWImage { + void *parent; + bool is_init; + uint32_t width; + uint32_t height; + uint32_t idx; + + pixman_image_t *srcs[VCSWIMAGE_MAX_BUF]; + pixman_image_t *dsts[VCSWIMAGE_MAX_BUF]; +} VCSWImage; + +void *imagemgr_create(void *parent) +{ + VCSWImage *swimage = g_new0(VCSWImage, 1); + swimage->parent = parent; + + return (void *)swimage; +} + +int imagemgr_init(void *mgr, const char *inPath) +{ + return 1; +} + +void imagemgr_reset(void *mgr) +{ +} + +void imagemgr_release(void *mgr) +{ + int i; + VCSWImage *swimage = (VCSWImage *)mgr; + + for (i = 0; i < VCSWIMAGE_MAX_BUF; i++) { + if (swimage->srcs[i]) { + pixman_image_unref(swimage->srcs[i]); + } + if (swimage->dsts[i]) { + pixman_image_unref(swimage->dsts[i]); + } + } + g_free(swimage); + swimage = NULL; +} + +void imagemgr_prepare(void *mgr) +{ + int i, val; + time_t t; + pixman_color_t color; + VCSWImage *swimage = (VCSWImage *)mgr; + + srand((unsigned) time(&t)); + + for (i = 0; i < VCSWIMAGE_MAX_BUF; i++) { + val = rand(); + + switch (val % 3) { + case 0: + color.alpha = 0x0000; + color.red = (val % 256) << 8; + color.green = 0x0000; + color.blue = 0x0000; + break; + case 1: + color.alpha = 0x0000; + color.red = 0x0000; + color.green = (val % 256) << 8; + color.blue = 0x0000; + break; + case 2: + color.alpha = 0x0000; + color.red = 0x0000; + color.green = 0x0000; + color.blue = (val % 256) << 8; + break; + default: + /* error */ + break; + } + + if (swimage->srcs[i]) { + pixman_image_unref(swimage->srcs[i]); + } + swimage->srcs[i] = pixman_image_create_solid_fill(&color); + } + +} + +bool imagemgr_is_init(void *mgr) +{ + VCSWImage *swimage = (VCSWImage *)mgr; + return swimage->is_init; +} + +void imagemgr_set_resolution(void *mgr, int w, int h) +{ + int i; + VCSWImage *swimage = (VCSWImage *)mgr; + + if (w == swimage->width && h == swimage->height) { + return; + } else { + swimage->width = w; + swimage->height = h; + } + + for (i = 0; i < VCSWIMAGE_MAX_BUF; i++) { + if (swimage->dsts[i]) { + pixman_image_unref(swimage->dsts[i]); + } + swimage->dsts[i] = pixman_image_create_bits(PIXMAN_r8g8b8, + w, h, NULL, w * 3); + pixman_image_composite(PIXMAN_OP_SRC, + swimage->srcs[i], NULL, swimage->dsts[i], + 0, 0, 0, 0, 0, 0, w, h); + } +} + +void *imagemgr_get_data(void *mgr) +{ + void *buf = NULL; + VCSWImage *swimage = (VCSWImage *)mgr; + + buf = pixman_image_get_data(swimage->dsts[swimage->idx++]); + if (swimage->idx == VCSWIMAGE_MAX_BUF) { + swimage->idx = 0; + } + + return buf; +} + +void imagemgr_adjust_ctrl(void *mgr, + unsigned int ctrl_id, + int ctrl_value) +{ +} diff --git a/tizen/src/hw/pci/maru_camera_virtual.c b/tizen/src/hw/pci/maru_camera_virtual.c new file mode 100644 index 0000000000..9894eec580 --- /dev/null +++ b/tizen/src/hw/pci/maru_camera_virtual.c @@ -0,0 +1,650 @@ +/* + * Implementation of MARU Virtual Camera device by PCI bus + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung Jo + * Sangho Park + * + * 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 + * + * with Qt5 QImage class + */ + +#include "qemu-common.h" +#include "qemu/timer.h" +#include "sysemu/kvm.h" +#include "emul_state.h" +#include "maru_camera.h" +#include "videodev2_min.h" +#include "maru_camera_convert.h" +#include "maru_camera_image.h" +#include "debug_ch.h" + +MULTI_DEBUG_CHANNEL(tizen, camera); + +/* Controls the frame rate + Delay time for the next image display */ +#define MC_DEFAULT_MS 100 + +static uint32_t support_fmts[] = { + V4L2_PIX_FMT_YUYV, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, +}; + +struct MCFrame { + uint32_t width; + uint32_t height; +}; + +static struct MCFrame support_frames[] = { + { 640, 480 }, + { 352, 288 }, + { 320, 240 }, + { 176, 144 }, + { 160, 120 }, +}; + +struct MCControls { + uint32_t id; + int32_t min; + int32_t max; + int32_t step; + int32_t init_val; + int32_t cur_val; +}; + +enum { + VC_CID_BRIGHTNESS, /* V4L2_CID_BRIGHTNESS */ + VC_CID_CONTRAST, /* V4L2_CID_CONTRAST */ + VC_CID_SATURATION, /* V4L2_CID_SATURATION */ + VC_CID_SHARPNESS, /* V4L2_CID_SHARPNESS */ + VC_CID_MAX, +}; + +static uint32_t idx_to_cid[VC_CID_MAX] = { + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_SHARPNESS, +}; + +typedef struct MCBuffer { + void *data; + size_t size; +} MCBuffer; + +struct MCStoredFrame { + void *data; + uint32_t pixelformat; + uint32_t width; + uint32_t height; + uint32_t size; +}; + +typedef struct MCBackendVirt { + MaruCamBackend base; + + QEMUTimer *timer; + struct MCControls ctrl_tbl[VC_CID_MAX]; + uint32_t src_fmt; + uint32_t dst_fmt; + uint32_t width; + uint32_t height; + void *imagemgr; +} MCBackendVirt; + +static void backend_virt_reset_ctrls(MCBackendVirt *backend) +{ + uint32_t i; + for (i = 0; i < VC_CID_MAX; i++) { + backend->ctrl_tbl[i].id = idx_to_cid[i]; + backend->ctrl_tbl[i].min = MARUCAM_CTRL_VALUE_MIN; + backend->ctrl_tbl[i].max = MARUCAM_CTRL_VALUE_MAX; + backend->ctrl_tbl[i].step = MARUCAM_CTRL_VALUE_STEP; + backend->ctrl_tbl[i].init_val = MARUCAM_CTRL_VALUE_MID; + backend->ctrl_tbl[i].cur_val = MARUCAM_CTRL_VALUE_MID; + } +} + +static int is_streamon(MaruCamState *state) +{ + int st; + qemu_mutex_lock(&state->thread_mutex); + st = state->streamon; + qemu_mutex_unlock(&state->thread_mutex); + return (st == _MC_THREAD_STREAMON); +} + +static void backend_virt_update(void *opaque) +{ + void *src_buf, *dst_buf; + MaruCamState *state = (MaruCamState *)opaque; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + qemu_mutex_lock(&state->thread_mutex); + if (state->streamon) { + if (state->req_frame == 0) { + TRACE("there is no request\n"); + goto update_out; + } + src_buf = imagemgr_get_data(backend->imagemgr); + if (src_buf == NULL) { + ERR("[%s:%d] Failed to get buffer\n", __func__, __LINE__); + goto update_out; + } + + dst_buf = state->fb_ptr + state->buf_size * (state->req_frame - 1); + if (convert_frame(backend->src_fmt, backend->dst_fmt, + backend->width, backend->height, + (size_t)state->buf_size, src_buf, dst_buf, false) > 0) { + ERR("[%s:%d] Failed to convert buffer\n", __func__, __LINE__); + goto update_out; + } + state->req_frame = 0; /* clear request */ + state->isr |= 0x01; /* set a flag of rasing a interrupt */ + qemu_bh_schedule(state->tx_bh); + } +update_out: + qemu_mutex_unlock(&state->thread_mutex); + + timer_mod(backend->timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + MC_DEFAULT_MS); +} + +static void *manager_init_func(void *thread_param) +{ + MaruCamState *state = (MaruCamState *)thread_param; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + backend->imagemgr = imagemgr_create(backend); + + if (state->path && state->path[0] != '\0') { + /* using the image data from input files including default images */ + imagemgr_init(backend->imagemgr, state->path); + } else { + /* using the image data to be generated internally */ + imagemgr_init(backend->imagemgr, NULL); + } + + backend->height = support_frames[0].height; + backend->width = support_frames[0].width; + backend->dst_fmt = support_fmts[0]; + backend->src_fmt = V4L2_PIX_FMT_RGB24; + + imagemgr_prepare(backend->imagemgr); + imagemgr_set_resolution(backend->imagemgr, + backend->width, + backend->height); + + return NULL; +} + +static void backend_virt_init(MaruCamState *state) +{ + qemu_thread_create(&state->thread_id, + "marucam-init-virtual", + manager_init_func, + (void *)state, + QEMU_THREAD_DETACHED); +} + +static void backend_virt_reset(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + imagemgr_reset(backend->imagemgr); +} + +static void backend_virt_release(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + imagemgr_release(backend->imagemgr); + g_free(backend); + backend = NULL; +} + +static void backend_virt_open(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + if (backend->imagemgr == NULL) { + ERR("There is no camera engine\n"); + state->ret_val = ENODEV; + return; + } + + INFO("Opened\n"); + backend->timer = timer_new_ms(QEMU_CLOCK_REALTIME, + backend_virt_update, + state); + + /* Set default values */ + backend->height = support_frames[0].height; + backend->width = support_frames[0].width; + backend->dst_fmt = support_fmts[0]; + + backend_virt_reset_ctrls(backend); +} + +static void backend_virt_close(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + if (is_streamon(state)) { + state->backend->stream_off(state); + } + + timer_free(backend->timer); + backend->timer = NULL; + + INFO("Closed\n"); +} + +static void backend_virt_stream_on(MaruCamState *state) +{ + uint32_t width, height, pixfmt; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + width = backend->width; + height = backend->height; + pixfmt = backend->dst_fmt; + state->buf_size = get_sizeimage(pixfmt, width, height); + + INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n", + (char)(pixfmt), (char)(pixfmt >> 8), + (char)(pixfmt >> 16), (char)(pixfmt >> 24), + width, height, state->buf_size); + INFO("Starting preview\n"); + + timer_mod(backend->timer, + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + MC_DEFAULT_MS); + + qemu_mutex_lock(&state->thread_mutex); + state->streamon = _MC_THREAD_STREAMON; + qemu_mutex_unlock(&state->thread_mutex); + + INFO("Streaming on ......\n"); +} + +static void backend_virt_stream_off(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + INFO("...... Streaming off\n"); + qemu_mutex_lock(&state->thread_mutex); + state->streamon = _MC_THREAD_STREAMOFF; + qemu_mutex_unlock(&state->thread_mutex); + + state->buf_size = 0; + + INFO("Stopping preview\n"); + timer_del(backend->timer); +} + + +static void backend_virt_s_parm(MaruCamState *state) +{ +} + +static void backend_virt_g_parm(MaruCamState *state) +{ + struct v4l2_captureparm *cp = + (struct v4l2_captureparm *)state->io_ptr; + + /* We use default FPS of the webcam + * return a fixed value on guest ini file (1/30). + */ + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->timeperframe.numerator = 1; + cp->timeperframe.denominator = 30; +} + +static void backend_virt_s_fmt(MaruCamState *state) +{ + uint32_t pidx, fidx; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + struct v4l2_pix_format *f = (struct v4l2_pix_format *)state->io_ptr; + + for (fidx = 0; fidx < ARRAY_SIZE(support_frames); fidx++) { + if ((support_frames[fidx].width == f->width) && + (support_frames[fidx].height == f->height)) { + break; + } + } + if (fidx == ARRAY_SIZE(support_frames)) { + state->ret_val = EINVAL; + return; + } + for (pidx = 0; pidx < ARRAY_SIZE(support_fmts); pidx++) { + if (support_fmts[pidx] == f->pixelformat) { + break; + } + } + if (pidx == ARRAY_SIZE(support_fmts)) { + state->ret_val = EINVAL; + return; + } + + f->width = backend->width = support_frames[fidx].width; + f->height = backend->height = support_frames[fidx].height; + f->pixelformat = backend->dst_fmt = support_fmts[pidx]; + + f->field = V4L2_FIELD_NONE; + f->bytesperline = get_bytesperline(backend->dst_fmt, + backend->width); + f->sizeimage = get_sizeimage(backend->dst_fmt, + backend->width, + backend->height); + f->colorspace = 0; + f->priv = 0; + + imagemgr_set_resolution(backend->imagemgr, + backend->width, + backend->height); + + TRACE("Set the format: w:h(%dx%d), fmt(0x%x), " + "bytesperline(%d), sizeimage(%d), colorspace(%d)\n", + f->width, f->height, f->pixelformat, f->bytesperline, + f->sizeimage, f->colorspace); +} + +static void backend_virt_g_fmt(MaruCamState *state) +{ + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + struct v4l2_pix_format *f = (struct v4l2_pix_format *)state->io_ptr; + + f->width = backend->width; + f->height = backend->height; + f->pixelformat = backend->dst_fmt; + f->field = V4L2_FIELD_NONE; + f->bytesperline = get_bytesperline(backend->dst_fmt, + backend->width); + f->sizeimage = get_sizeimage(backend->dst_fmt, + backend->width, + backend->height); + f->colorspace = 0; + f->priv = 0; + + TRACE("Get the format: w:h(%dx%d), fmt(0x%x), " + "bytesperline(%d), sizeimage(%d), colorspace(%d)\n", + f->width, f->height, f->pixelformat, f->bytesperline, + f->sizeimage, f->colorspace); +} + +static void backend_virt_try_fmt(MaruCamState *state) +{ + uint32_t i; + struct v4l2_pix_format *f = (struct v4l2_pix_format *)state->io_ptr; + + for (i = 0; i < ARRAY_SIZE(support_frames); i++) { + if ((support_frames[i].width == f->width) && + (support_frames[i].height == f->height)) { + break; + } + } + if (i == ARRAY_SIZE(support_frames)) { + state->ret_val = EINVAL; + return; + } + for (i = 0; i < ARRAY_SIZE(support_fmts); i++) { + if (support_fmts[i] == f->pixelformat) { + break; + } + } + if (i == ARRAY_SIZE(support_fmts)) { + state->ret_val = EINVAL; + return; + } + + f->field = V4L2_FIELD_NONE; + f->bytesperline = get_bytesperline(f->pixelformat, + f->width); + f->sizeimage = get_sizeimage(f->pixelformat, + f->width, + f->height); + f->colorspace = 0; + f->priv = 0; + + + TRACE("Check the format: w:h(%dx%d), pix_fmt(0x%x), " + "bytesperline(%d), sizeimage(%d), colorspace(%d)\n", + f->width, f->height, f->pixelformat, f->bytesperline, + f->sizeimage, f->colorspace); +} + +static void backend_virt_enum_fmt(MaruCamState *state) +{ + struct v4l2_fmtdesc *f = (struct v4l2_fmtdesc *)state->io_ptr; + + if (f->index >= ARRAY_SIZE(support_fmts)) { + state->ret_val = EINVAL; + return; + } + + f->flags = 0; /* flags = NONE */ + f->pixelformat = support_fmts[f->index]; /* pixelformat */ + + /* set description */ + switch (support_fmts[f->index]) { + case V4L2_PIX_FMT_YUYV: + pstrcpy((char *)f->description, sizeof(f->description), "YUYV"); + break; + case V4L2_PIX_FMT_YUV420: + pstrcpy((char *)f->description, sizeof(f->description), "YU12"); + break; + case V4L2_PIX_FMT_YVU420: + pstrcpy((char *)f->description, sizeof(f->description), "YV12"); + break; + default: + ERR("Invalid fixel format\n"); + state->ret_val = EINVAL; + break; + } +} + +static void backend_virt_query_ctrl(MaruCamState *state) +{ + struct v4l2_queryctrl *qc = (struct v4l2_queryctrl *)state->io_ptr; + + /* NOTICE: Tizen MMFW hardcoded for control name + Do Not Modified the name + */ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + TRACE("Query : BRIGHTNESS\n"); + pstrcpy((char *)qc->name, sizeof(qc->name), "brightness"); + break; + case V4L2_CID_CONTRAST: + TRACE("Query : CONTRAST\n"); + pstrcpy((char *)qc->name, sizeof(qc->name), "contrast"); + break; + case V4L2_CID_SATURATION: + TRACE("Query : SATURATION\n"); + pstrcpy((char *)qc->name, sizeof(qc->name), "saturation"); + break; + case V4L2_CID_SHARPNESS: + TRACE("Query : SHARPNESS\n"); + pstrcpy((char *)qc->name, sizeof(qc->name), "sharpness"); + break; + default: + ERR("[%s] Invalid control ID: 0x%x\n", __func__, qc->id); + state->ret_val = EINVAL; + return; + } + + /* set fixed values by FW configuration file */ + qc->minimum = MARUCAM_CTRL_VALUE_MIN; /* minimum */ + qc->maximum = MARUCAM_CTRL_VALUE_MAX; /* maximum */ + qc->step = MARUCAM_CTRL_VALUE_STEP; /* step */ + qc->default_value = MARUCAM_CTRL_VALUE_MID; /* default_value */ + qc->flags = V4L2_CTRL_FLAG_SLIDER; + + TRACE("Query Control: id(0x%x), name(%s), min(%d), max(%d), step(%d), " + "def_value(%d), flags(0x%x)\n", + qc->id, qc->name, qc->minimum, qc->maximum, + qc->step, qc->default_value, qc->flags); +} + +static void backend_virt_s_ctrl(MaruCamState *state) +{ + uint32_t i; + struct v4l2_control *ctrl = (struct v4l2_control *)state->io_ptr; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + i = VC_CID_BRIGHTNESS; + TRACE("%d is set to the value of the BRIGHTNESS\n", ctrl->value); + break; + case V4L2_CID_CONTRAST: + i = VC_CID_CONTRAST; + TRACE("%d is set to the value of the CONTRAST\n", ctrl->value); + break; + case V4L2_CID_SATURATION: + i = VC_CID_SATURATION; + TRACE("%d is set to the value of the SATURATION\n", ctrl->value); + break; + case V4L2_CID_SHARPNESS: + i = VC_CID_SHARPNESS; + TRACE("%d is set to the value of the SHARPNESS\n", ctrl->value); + break; + default: + ERR("[%s] Not supported control: 0x%x\n", __func__, ctrl->id); + state->ret_val = EINVAL; + return; + } + backend->ctrl_tbl[i].cur_val = ctrl->value; + imagemgr_adjust_ctrl(backend->imagemgr, ctrl->id, ctrl->value); +} + +static void backend_virt_g_ctrl(MaruCamState *state) +{ + uint32_t i; + struct v4l2_control *ctrl = (struct v4l2_control *)state->io_ptr; + MCBackendVirt *backend = (MCBackendVirt *)(state->backend); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + i = VC_CID_BRIGHTNESS; + TRACE("Gets the value of the BRIGHTNESS\n"); + break; + case V4L2_CID_CONTRAST: + i = VC_CID_CONTRAST; + TRACE("Gets the value of the CONTRAST\n"); + break; + case V4L2_CID_SATURATION: + i = VC_CID_SATURATION; + TRACE("Gets the value of the SATURATION\n"); + break; + case V4L2_CID_SHARPNESS: + i = VC_CID_SHARPNESS; + TRACE("Gets the value of the SHARPNESS\n"); + break; + default: + ERR("[%s] Not supported control: 0x%x\n", __func__, ctrl->id); + state->ret_val = EINVAL; + return; + } + + ctrl->value = backend->ctrl_tbl[i].cur_val; + TRACE("Value: %d\n", ctrl->value); +} + +static void backend_virt_enum_fsizes(MaruCamState *state) +{ + uint32_t i; + struct v4l2_frmsizeenum *fsize = + (struct v4l2_frmsizeenum *)state->io_ptr; + + if (fsize->index >= ARRAY_SIZE(support_frames)) { + state->ret_val = EINVAL; + return; + } + for (i = 0; i < ARRAY_SIZE(support_fmts); i++) { + if (support_fmts[i] == fsize->pixel_format) { + break; + } + } + + if (i == ARRAY_SIZE(support_fmts)) { + state->ret_val = EINVAL; + return; + } + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = support_frames[fsize->index].width; + fsize->discrete.height = support_frames[fsize->index].height; +} + +static void backend_virt_enum_fintv(MaruCamState *state) +{ + struct v4l2_frmivalenum *fival = + (struct v4l2_frmivalenum *)state->io_ptr; + + /* switch by index) */ + switch (fival->index) { + case 0: + /* we only use 1/30 frame interval */ + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = 30; + break; + default: + state->ret_val = EINVAL; + return; + } +} + +MaruCamBackend *marucam_virtual_backend_create(MaruCamState *state) +{ + MCBackendVirt *backend_virt; + + backend_virt = g_new0(MCBackendVirt, 1); + if (backend_virt == NULL) { + ERR("Failed to allocate memory for the virtual backend\n"); + return NULL; + } + + + backend_virt->base.state = state; + backend_virt->base.init = backend_virt_init; + backend_virt->base.reset = backend_virt_reset; + backend_virt->base.release = backend_virt_release; + backend_virt->base.open = backend_virt_open; + backend_virt->base.close = backend_virt_close; + backend_virt->base.stream_on = backend_virt_stream_on; + backend_virt->base.stream_off = backend_virt_stream_off; + backend_virt->base.enum_fmt = backend_virt_enum_fmt; + backend_virt->base.try_fmt = backend_virt_try_fmt; + backend_virt->base.s_fmt = backend_virt_s_fmt; + backend_virt->base.g_fmt = backend_virt_g_fmt; + backend_virt->base.s_parm = backend_virt_s_parm; + backend_virt->base.g_parm = backend_virt_g_parm; + backend_virt->base.query_ctrl = backend_virt_query_ctrl; + backend_virt->base.s_ctrl = backend_virt_s_ctrl; + backend_virt->base.g_ctrl = backend_virt_g_ctrl; + backend_virt->base.enum_framesizes = backend_virt_enum_fsizes; + backend_virt->base.enum_frameintervals = backend_virt_enum_fintv; + + return &backend_virt->base; +} diff --git a/tizen/src/hw/pci/maru_camera_win32.c b/tizen/src/hw/pci/maru_camera_win32.c index 3ad02cc8dc..038d2edbcf 100644 --- a/tizen/src/hw/pci/maru_camera_win32.c +++ b/tizen/src/hw/pci/maru_camera_win32.c @@ -2495,7 +2495,7 @@ static void backend_win_enum_fintv(MaruCamState *state) } } -MaruCamBackend *marucam_backend_create(MaruCamState *state) +MaruCamBackend *marucam_native_backend_create(MaruCamState *state) { MCBackendWin *backend_win;