diff options
-rw-r--r-- | android/avd/hardware-properties.ini | 104 | ||||
-rw-r--r-- | android/camera/camera-capture-linux.c | 3 | ||||
-rwxr-xr-x | android/camera/camera-capture-windows.c | 4 | ||||
-rwxr-xr-x | android/camera/camera-common.h | 8 | ||||
-rw-r--r-- | android/camera/camera-service.c | 212 | ||||
-rw-r--r-- | android/camera/camera-service.h | 3 | ||||
-rw-r--r-- | android/cmdline-options.h | 1 | ||||
-rw-r--r-- | android/help.c | 19 | ||||
-rw-r--r-- | android/main.c | 120 | ||||
-rw-r--r-- | qemu-options.hx | 3 | ||||
-rw-r--r-- | vl-android.c | 9 |
11 files changed, 441 insertions, 45 deletions
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini index 6a904d6..fb53536 100644 --- a/android/avd/hardware-properties.ini +++ b/android/avd/hardware-properties.ini @@ -240,6 +240,110 @@ default = back abstract = Fake camera control description = Must be 'back', if fake camera is facing back, 'front', if fake camera is facing front, or 'off' if fake camera is disabled. +# Number of emulated web cameras +# +name = hw.webcam.count +type = integer +default = 6 +abstract = Number of emulated web cameras +description = Defines number of web cameras to emulate. 0 disables webcam emulation. + +# Defines name of the emulated webcam with index 0 +# +name = hw.webcam.0.name +type = string +default = webcam0 +abstract = Name of the 1-st emulated web camera +description = Emulator-generated platform-independent name identifying a camera in the list of enumerated web cameras. + +# Defines name of the emulated webcam with index 1 +# +name = hw.webcam.1.name +type = string +default = webcam1 +abstract = Name of the 2-nd emulated web camera +description = Emulator-generated platform-independent camera name. + +# Defines name of the emulated webcam with index 2 +# +name = hw.webcam.2.name +type = string +default = webcam2 +abstract = Name of the 3-rd emulated web camera +description = Emulator-generated platform-independent camera name. + +# Defines name of the emulated webcam with index 3 +# +name = hw.webcam.3.name +type = string +default = webcam3 +abstract = Name of the 4-th emulated web camera +description = Emulator-generated platform-independent camera name. + +# Defines name of the emulated webcam with index 4 +# +name = hw.webcam.4.name +type = string +default = webcam4 +abstract = Name of the 5-th emulated web camera +description = Emulator-generated platform-independent camera name. + +# Defines name of the emulated webcam with index 5 +# +name = hw.webcam.5.name +type = string +default = webcam5 +abstract = Name of the 6-th emulated web camera +description = Emulator-generated platform-independent camera name. + +# Defines direction of the emulated webcam with index 0 +# +name = hw.webcam.0.direction +type = string +default = front +abstract = 1-st emulated web camera direction +description = Direction of the 1-st emulated web camera + +# Defines direction of the emulated webcam with index 1 +# +name = hw.webcam.1.direction +type = string +default = front +abstract = 2-nd emulated web camera direction +description = Direction of the 2-nd emulated web camera + +# Defines direction of the emulated webcam with index 2 +# +name = hw.webcam.2.direction +type = string +default = front +abstract = 3-rd emulated web camera direction +description = Direction of the 3-rd emulated web camera + +# Defines direction of the emulated webcam with index 3 +# +name = hw.webcam.3.direction +type = string +default = front +abstract = 4-th emulated web camera direction +description = Direction of the 4-th emulated web camera + +# Defines direction of the emulated webcam with index 4 +# +name = hw.webcam.4.direction +type = string +default = front +abstract = 5-th emulated web camera direction +description = Direction of the 5-th emulated web camera + +# Defines direction of the emulated webcam with index 5 +# +name = hw.webcam.5.direction +type = string +default = front +abstract = 6-th emulated web camera direction +description = Direction of the 6-th emulated web camera + # Maximum VM heap size # Higher values are required for high-dpi devices # Default will depend on RAM size. diff --git a/android/camera/camera-capture-linux.c b/android/camera/camera-capture-linux.c index 072d06e..50324f0 100644 --- a/android/camera/camera-capture-linux.c +++ b/android/camera/camera-capture-linux.c @@ -1048,6 +1048,9 @@ enumerate_camera_devices(CameraInfo* cis, int max) if (cd != NULL) { LinuxCameraDevice* lcd = (LinuxCameraDevice*)cd->opaque; if (!_camera_device_get_info(lcd, cis + found)) { + char user_name[24]; + sprintf(user_name, "webcam%d", found); + cis[found].display_name = ASTRDUP(user_name); cis[found].in_use = 0; found++; } diff --git a/android/camera/camera-capture-windows.c b/android/camera/camera-capture-windows.c index e5120ab..0fb172e 100755 --- a/android/camera/camera-capture-windows.c +++ b/android/camera/camera-capture-windows.c @@ -504,7 +504,11 @@ enumerate_camera_devices(CameraInfo* cis, int max) * but the actual numbers may vary). */ cis[found].frame_sizes = (CameraFrameDim*)malloc(sizeof(CameraFrameDim)); if (cis[found].frame_sizes != NULL) { + char disp_name[24]; + sprintf(disp_name, "webcam%d", found); + cis[found].display_name = ASTRDUP(disp_name); cis[found].device_name = ASTRDUP(name); + cis[found].direction = ASTRDUP("front"); cis[found].inp_channel = inp_channel; cis[found].frame_sizes->width = wcd->frame_bitmap->bmiHeader.biWidth; cis[found].frame_sizes->height = wcd->frame_bitmap->bmiHeader.biHeight; diff --git a/android/camera/camera-common.h b/android/camera/camera-common.h index 0cf8cea..a3fdd5f 100755 --- a/android/camera/camera-common.h +++ b/android/camera/camera-common.h @@ -88,12 +88,16 @@ typedef struct CameraFrameDim { * representing that camera. */ typedef struct CameraInfo { + /* User-friendly camera display name. */ + char* display_name; /* Device name for the camera. */ char* device_name; /* Input channel for the camera. */ int inp_channel; /* Pixel format chosen for the camera. */ uint32_t pixel_format; + /* Direction the camera is facing: 'front', or 'back' */ + char* direction; /* Array of frame sizes supported for the pixel format chosen for the camera. * The size of the array is defined by the frame_sizes_num field of this * structure. */ @@ -120,8 +124,12 @@ static __inline__ CameraInfo* _camera_info_alloc(void) static __inline__ void _camera_info_free(CameraInfo* ci) { if (ci != NULL) { + if (ci->display_name != NULL) + free(ci->display_name); if (ci->device_name != NULL) free(ci->device_name); + if (ci->direction != NULL) + free(ci->direction); if (ci->frame_sizes != NULL) free(ci->frame_sizes); AFREE(ci); diff --git a/android/camera/camera-service.c b/android/camera/camera-service.c index a35f595..96d3c44 100644 --- a/android/camera/camera-service.c +++ b/android/camera/camera-service.c @@ -19,6 +19,7 @@ */ #include "qemu-common.h" +#include "android/globals.h" /* for android_hw */ #include "android/hw-qemud.h" #include "android/utils/misc.h" #include "android/utils/system.h" @@ -62,48 +63,6 @@ struct CameraServiceDesc { static CameraServiceDesc _camera_service_desc; /******************************************************************************** - * CameraServiceDesc API - *******************************************************************************/ - -/* Initializes camera service descriptor. - */ -static void -_camera_service_init(CameraServiceDesc* csd) -{ - /* Enumerate camera devices connected to the host. */ - csd->camera_count = enumerate_camera_devices(csd->camera_info, MAX_CAMERA); - if (csd->camera_count >= 0) { - D("%s: Enumerated %d cameras connected to the host", - __FUNCTION__, csd->camera_count); - } else { - E("%s: Unable to enumerate camera devices", __FUNCTION__); - csd->camera_count = 0; - return; - } -} - -/* Gets camera information for the given camera device name. - * Param: - * cs - Initialized camera service descriptor. - * name - Camera device name to look up the information for. - * Return: - * Camera information pointer on success, or NULL if no camera information has - * been found for the given device name. Note that camera information returned - * from this routine is constant. - */ -static CameraInfo* -_camera_service_get_camera_info(CameraServiceDesc* cs, const char* name) -{ - int n; - for (n = 0; n < cs->camera_count; n++) { - if (!strcmp(cs->camera_info[n].device_name, name)) { - return &cs->camera_info[n]; - } - } - return NULL; -} - -/******************************************************************************** * Helper routines *******************************************************************************/ @@ -357,7 +316,7 @@ _append_string(char** str_buf, size_t* str_buf_size, const char* str) } /* Represents camera information as a string formatted as follows: - * 'name=<devname> channel=<num> pix=<format> framedims=<widh1xheight1,widh2xheight2,widhNxheightN>\n' + * 'name=<devname> channel=<num> pix=<format> facing=<direction> framedims=<widh1xheight1,...>\n' * Param: * ci - Camera information descriptor to convert into a string. * str - Pointer to the string buffer where to save the converted camera @@ -394,6 +353,12 @@ _camera_info_to_string(const CameraInfo* ci, char** str, size_t* str_size) { if (res) { return res; } + /* Append direction. */ + snprintf(tmp, sizeof(tmp), "dir=%s ", ci->direction); + res = _append_string(str, str_size, tmp); + if (res) { + return res; + } /* Append supported frame sizes. */ snprintf(tmp, sizeof(tmp), "framedims=%dx%d", ci->frame_sizes[0].width, ci->frame_sizes[0].height); @@ -414,6 +379,143 @@ _camera_info_to_string(const CameraInfo* ci, char** str, size_t* str_size) { return _append_string(str, str_size, "\n"); } +/* Gets camera information matching a display name. + * Param: + * disp_name - Display name to match. + * arr - Array of camera informations. + * num - Number of elements in the array. + * Return: + * Matching camera information, or NULL if matching camera information for the + * given display name has not been found in the array. + */ +static CameraInfo* +_camera_info_get_by_display_name(const char* disp_name, CameraInfo* arr, int num) +{ + int n; + for (n = 0; n < num; n++) { + if (arr[n].display_name != NULL && !strcmp(arr[n].display_name, disp_name)) { + return &arr[n]; + } + } + return NULL; +} + +/* Gets camera information matching a device name. + * Param: + * device_name - Device name to match. + * arr - Array of camera informations. + * num - Number of elements in the array. + * Return: + * Matching camera information, or NULL if matching camera information for the + * given device name has not been found in the array. + */ +static CameraInfo* +_camera_info_get_by_device_name(const char* device_name, CameraInfo* arr, int num) +{ + int n; + for (n = 0; n < num; n++) { + if (arr[n].device_name != NULL && !strcmp(arr[n].device_name, device_name)) { + return &arr[n]; + } + } + return NULL; +} + +/******************************************************************************** + * CameraServiceDesc API + *******************************************************************************/ + +/* Initializes camera service descriptor. + */ +static void +_camera_service_init(CameraServiceDesc* csd) +{ + CameraInfo ci[MAX_CAMERA]; + int connected_cnt; + int i; + + /* Enumerate camera devices connected to the host. */ + memset(ci, 0, sizeof(CameraInfo) * MAX_CAMERA); + memset(csd->camera_info, 0, sizeof(CameraInfo) * MAX_CAMERA); + csd->camera_count = 0; + connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA); + if (connected_cnt <= 0) { + /* Nothing is connected - nothing to emulate. */ + return; + } + + /* For each webcam declared in hw.ini find an actual camera information + * descriptor, and save it into the service descriptor for the emulation. */ + for (i = 0; i < android_hw->hw_webcam_count; i++) { + const char* disp_name; + const char* dir; + CameraInfo* found; + + switch (i) { + case 0: + disp_name = android_hw->hw_webcam_0_name; + dir = android_hw->hw_webcam_0_direction; + break; + case 1: + disp_name = android_hw->hw_webcam_1_name; + dir = android_hw->hw_webcam_1_direction; + break; + case 2: + disp_name = android_hw->hw_webcam_2_name; + dir = android_hw->hw_webcam_2_direction; + break; + case 3: + disp_name = android_hw->hw_webcam_3_name; + dir = android_hw->hw_webcam_3_direction; + break; + case 4: + disp_name = android_hw->hw_webcam_4_name; + dir = android_hw->hw_webcam_4_direction; + break; + case 5: + default: + disp_name = android_hw->hw_webcam_5_name; + dir = android_hw->hw_webcam_5_direction; + break; + } + found = _camera_info_get_by_display_name(disp_name, ci, connected_cnt); + if (found != NULL) { + /* Save to the camera info array that will be used by the service. + * Note that we just copy everything over, and NULL the source + * record. */ + memcpy(csd->camera_info + csd->camera_count, found, sizeof(CameraInfo)); + /* Update direction parameter. */ + if (csd->camera_info[csd->camera_count].direction != NULL) { + free(csd->camera_info[csd->camera_count].direction); + } + csd->camera_info[csd->camera_count].direction = ASTRDUP(dir); + D("Camera %d '%s' connected to '%s' facing %s using %.4s pixel format", + csd->camera_count, csd->camera_info[csd->camera_count].display_name, + csd->camera_info[csd->camera_count].device_name, + csd->camera_info[csd->camera_count].direction, + (const char*)(&csd->camera_info[csd->camera_count].pixel_format)); + csd->camera_count++; + memset(found, 0, sizeof(CameraInfo)); + } + } +} + +/* Gets camera information for the given camera device name. + * Param: + * cs - Initialized camera service descriptor. + * device_name - Camera's device name to look up the information for. + * Return: + * Camera information pointer on success, or NULL if no camera information has + * been found for the given device name. + */ +static CameraInfo* +_camera_service_get_camera_info_by_device_name(CameraServiceDesc* cs, + const char* device_name) +{ + return _camera_info_get_by_device_name(device_name, cs->camera_info, + cs->camera_count); +} + /******************************************************************************** * Helpers for handling camera client queries *******************************************************************************/ @@ -743,7 +845,7 @@ _camera_client_create(CameraServiceDesc* csd, const char* param) * then use device name reported in the list to connect to an emulated camera * service. So, if camera information for the given device name is not found * in the array, we fail this connection due to protocol violation. */ - ci = _camera_service_get_camera_info(csd, cc->device_name); + ci = _camera_service_get_camera_info_by_device_name(csd, cc->device_name); if (ci == NULL) { E("%s: Cannot find camera info for device '%s'", __FUNCTION__, cc->device_name); @@ -1303,3 +1405,25 @@ android_camera_service_init(void) D("%s: Registered '%s' qemud service", __FUNCTION__, SERVICE_NAME); } } + +void +android_list_web_cameras(void) +{ + CameraInfo ci[MAX_CAMERA]; + int connected_cnt; + int i; + + /* Enumerate camera devices connected to the host. */ + connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA); + if (connected_cnt <= 0) { + return; + } + + printf("List of web cameras connected to the computer:\n"); + for (i = 0; i < connected_cnt; i++) { + printf(" Camera '%s' is connected to device '%s' on channel %d using pixel format '%.4s'\n", + ci[i].display_name, ci[i].device_name, ci[i].inp_channel, + (const char*)&ci[i].pixel_format); + } + printf("\n"); +} diff --git a/android/camera/camera-service.h b/android/camera/camera-service.h index 6794187..e8df288 100644 --- a/android/camera/camera-service.h +++ b/android/camera/camera-service.h @@ -24,4 +24,7 @@ /* Initializes camera emulation service over qemu pipe. */ extern void android_camera_service_init(void); +/* Lists available web cameras. */ +extern void android_list_web_cameras(void); + #endif /* ANDROID_CAMERA_CAMERA_SERVICE_H_ */ diff --git a/android/cmdline-options.h b/android/cmdline-options.h index 3bc2197..0cf358f 100644 --- a/android/cmdline-options.h +++ b/android/cmdline-options.h @@ -157,6 +157,7 @@ OPT_PARAM( attach_core, "<console socket>", "attach to a running core process" ) OPT_PARAM( gpu, "<mode>", "set hardware OpenGLES emulation mode" ) OPT_PARAM( fake_camera, "<mode>", "set fake camera emulation mode" ) +OPT_LIST( webcam, "name=<name>[,dir=<direction>]", "setup web camera emulation" ) #undef CFG_FLAG #undef CFG_PARAM diff --git a/android/help.c b/android/help.c index 7f89376..4087911 100644 --- a/android/help.c +++ b/android/help.c @@ -1469,6 +1469,25 @@ help_fake_camera(stralloc_t* out) ); } +static void +help_webcam(stralloc_t* out) +{ + PRINTF( + " Use -webcam off to disable web camera emulation.\n" + " Use -webcam list to list web cameras available for emulation.\n" + " Use -webcam name=<name>[,dir=<direction>] to setup parameters for web camera emulation.\n" + + " <name> platform-independent name identifying emulated camera device.\n" + " use '-webcam list' to obtain the list of emulated camera devices.\n" + " <direction> defines direction the camera is facing. Valid values are:\n\n" + + " front -> emulate camera as facing front\n" + " back -> emulate camera as facing back\n\n" + + " Default direction value for emulated web camera is 'front'\n\n" + ); +} + #define help_no_skin NULL #define help_netspeed help_shaper #define help_netdelay help_shaper diff --git a/android/main.c b/android/main.c index 314779f..c2f8663 100644 --- a/android/main.c +++ b/android/main.c @@ -155,6 +155,65 @@ _adjustPartitionSize( const char* description, return convertMBToBytes(imageMB); } +/* Parses a -webcam option, extracting 'name', and 'dir' values. + * Param: + * param - -webcam option, that should be formatted as such: + * name=<name>[,dir=<direction>] + * name, name_size - buffer (and its size) where to receive <name> + * dir, dir_size - buffer (and its size) where to receive <direction> + */ +static void +_parseWebcamOption(const char* param, + char* name, size_t name_size, + char* dir, size_t dir_size) +{ + const char* dr; + const char* wc_opt = param; + + /* Must start with 'name=' */ + if (strlen(wc_opt) <= 5 || memcmp(wc_opt, "name=", 5)) { + derror("Invalid value for -webcam parameter: %s\n", param); + exit(1); + } + + /* Move on to 'name' value. */ + wc_opt += 5; + dr = strchr(wc_opt, ','); + if (dr == NULL) { + dr = wc_opt + strlen(wc_opt); + } + + /* Make sure that <name> fits */ + if ((dr - wc_opt) < name_size) { + memcpy(name, wc_opt, dr - wc_opt); + name[dr - wc_opt] = '\0'; + if (*dr == '\0') { + /* Default direction value is 'front' */ + strcpy(dir, "front"); + return; + } else { + dr++; + } + } else { + derror("Invalid <name> value for -webcam parameter: %s\n", param); + exit(1); + } + + /* Parse 'dir'. Must begin with 'dir=' */ + if (strlen(dr) <= 4 || memcmp(dr, "dir=", 4)) { + derror("Invalid value for -webcam parameter: %s\n", param); + exit(1); + } + dr += 4; + /* Check the bounds, and the values */ + if (strlen(dr) >= dir_size || (strcmp(dr, "front") && strcmp(dr, "back"))) { + derror("Invalid <direction> value for -webcam parameter: %s\n" + "Valid values are: 'front', or 'back'\n", param); + exit(1); + } + strcpy(dir, dr); +} + int main(int argc, char **argv) { char tmp[MAX_PATH]; @@ -1098,6 +1157,67 @@ int main(int argc, char **argv) } } + if (opts->webcam != NULL) { + ParamList* pl = opts->webcam; + int webcam_num = 0; + for ( ; pl != NULL; pl = pl->next ) { + char webcam_name[64]; + char webcam_dir[16]; + if (!strcmp(pl->param, "off")) { + /* If 'off' is passed, there must be no other -webcam options. */ + if (webcam_num || pl->next != NULL) { + derror("'-webcam off' cannot be combined with other -webcam otions\n"); + exit(1); + } + break; + } + if (!strcmp(pl->param, "list")) { + /* If 'list' is passed, there must be no other -webcam options. */ + if (webcam_num || pl->next != NULL) { + derror("'-webcam list' cannot be combined with other -webcam otions\n"); + exit(1); + } + args[n++] = "-list-webcam"; + break; + } + /* Extract name, and direction */ + _parseWebcamOption(pl->param, webcam_name, sizeof(webcam_name), + webcam_dir, sizeof(webcam_dir)); + /* Save them to appropriate field in hw.ini */ + switch (webcam_num) { + case 0: + hw->hw_webcam_0_name = ASTRDUP(webcam_name); + hw->hw_webcam_0_direction = ASTRDUP(webcam_dir); + break; + case 1: + hw->hw_webcam_1_name = ASTRDUP(webcam_name); + hw->hw_webcam_1_direction = ASTRDUP(webcam_dir); + break; + case 2: + hw->hw_webcam_2_name = ASTRDUP(webcam_name); + hw->hw_webcam_2_direction = ASTRDUP(webcam_dir); + break; + case 3: + hw->hw_webcam_3_name = ASTRDUP(webcam_name); + hw->hw_webcam_3_direction = ASTRDUP(webcam_dir); + break; + case 4: + hw->hw_webcam_4_name = ASTRDUP(webcam_name); + hw->hw_webcam_4_direction = ASTRDUP(webcam_dir); + break; + case 5: + hw->hw_webcam_5_name = ASTRDUP(webcam_name); + hw->hw_webcam_5_direction = ASTRDUP(webcam_dir); + break; + default: + derror("Too many -webcam options. Maximum number of -webcam options is 6\n"); + exit(1); + } + webcam_num++; + } + hw->hw_webcam_count = webcam_num; + } + /* physical memory is now in hw->hw_ramSize */ hw->avd_name = ASTRDUP(avdInfo_getName(avd)); diff --git a/qemu-options.hx b/qemu-options.hx index 76432a5..880025e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1787,4 +1787,7 @@ DEF("audio-test-out", 0, QEMU_OPTION_audio_test_out, \ DEF("snapshot-no-time-update", 0, QEMU_OPTION_snapshot_no_time_update, \ "-snapshot-no-time-update Disable time update when restoring snapshots\n") +DEF("list-webcam", 0, QEMU_OPTION_list_webcam, \ + "-list-webcam List web cameras available for emulation\n") + #endif /* ANDROID */ diff --git a/vl-android.c b/vl-android.c index f657258..f0b2ae8 100644 --- a/vl-android.c +++ b/vl-android.c @@ -2619,7 +2619,6 @@ int main(int argc, char **argv, char **envp) boot_property_init_service(); android_hw_control_init(); android_net_pipes_init(); - android_camera_service_init(); #ifdef CONFIG_KVM /* By default, force auto-detection for kvm */ @@ -3468,6 +3467,11 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_snapshot_no_time_update: android_snapshot_update_time = 0; break; + + case QEMU_OPTION_list_webcam: + android_list_web_cameras(); + exit(0); + default: os_parse_cmd_args(popt->index, optarg); } @@ -3741,6 +3745,9 @@ int main(int argc, char **argv, char **envp) boot_property_add("qemu.sf.fake_camera", "back"); } + /* Initialize camera emulation. */ + android_camera_service_init(); + if (android_op_cpu_delay) { char* end; long delay = strtol(android_op_cpu_delay, &end, 0); |