/* * Releases the control interface */ JNIEXPORT void JNICALL Java_au_edu_jcu_v4l4j_VideoDevice_doReleaseControlList(JNIEnv *e, jobject t, jlong o){ dprint(LOG_CALLS, "[CALL] Entering %s\n",__PRETTY_FUNCTION__); struct v4l4j_device *d = (struct v4l4j_device *) (uintptr_t) o; dprint(LOG_LIBVIDEO, "[LIBVIDEO] Calling release_control_list()\n"); release_control_list(d->vdev); }
/* send an HTMl page over the "newsockfd" socket with a list of V4L2 controls (brightness, contrast, ...) * as well as JPEG and fps controls */ void list_cap_param(int newsockfd,struct video_device *d) { char *page, *ptr; struct control_list *l = get_control_list(d); int i, v; XMALLOC(page, char *, PARAM_PAGE_SIZE); ptr = page; ptr += sprintf(ptr,"<html><body>\n"); //outputs JPEG quality control setting ptr += sprintf(ptr,"<form method=\"get\"><h4>JPEG quality</h4>Value: %d (min: 0, max: 100, step: 1)<br>\n", jpeg_quality); ptr += sprintf(ptr,"<input type=\"text\" name=\"val\" value=\"%d\" size=\"5\"> <input type=\"submit\" name=\"-1\" value=\"update\"></form>\n", jpeg_quality); write(newsockfd, page, strlen(page)); ptr = page; memset(page, 0, PARAM_PAGE_SIZE); //outputs frame rate control setting ptr += sprintf(ptr,"<form method=\"get\"><h4>Frame rate</h4>Value: %d (min: 1, max: 25, step: 1)<br>\n", requested_fps); ptr += sprintf(ptr,"<input type=\"text\" name=\"val\" value=\"%d\" size=\"3\"> <input type=\"submit\" name=\"-2\" value=\"update\"></form>\n", requested_fps); write(newsockfd, page, strlen(page)); ptr = page; memset(page, 0, PARAM_PAGE_SIZE); //outputs controls l = d->control; for(i = 0; i< l->count; i++) { if(get_control_value(d, l->controls[i].v4l2_ctrl, &v) != 0) { info(LOG_ERR, "Error getting value for control %s\n", l->controls[i].v4l2_ctrl->name); v = 0; } ptr += sprintf(ptr,"<form method=\"get\"><h4>%s</h4>Value: %d (min: %d, max: %d", l->controls[i].v4l2_ctrl->name, v, l->controls[i].v4l2_ctrl->minimum, l->controls[i].v4l2_ctrl->maximum); if(l->controls[i].count_menu!=0) { int j; ptr += sprintf(ptr,"\n)<select name=\"val\">\n"); for(j=0; j<l->controls[i].count_menu; j++){ ptr += sprintf(ptr, "<option value=\"%d\"%s>%d</option>\n",l->controls[i].v4l2_menu[j].index, v == l->controls[i].v4l2_menu[j].index ? " selected" : "", l->controls[i].v4l2_menu[j].index); } ptr += sprintf(ptr, "</select>\n"); } else { ptr += sprintf(ptr,", step: %d)<br>\n", l->controls[i].v4l2_ctrl->step); ptr += sprintf(ptr,"<input type=\"text\" name=\"val\" value=\"%d\" size=\"5\"> ", v); } ptr += sprintf(ptr, " <input type=\"submit\" name=\"%d\" value=\"update\"></form>\n", i); write(newsockfd, page, strlen(page)); ptr = page; memset(page, 0, PARAM_PAGE_SIZE); } //output end of HTML body ptr += sprintf(ptr,"</body></html>\n"); write(newsockfd, page, strlen(page)); XFREE(page); release_control_list(d); }
/* Reads the first few bytes of "sock" socket and decides what to do (send webcam stream or list of controls) * In the latter case (list of controls), more bytes are parsed to see whether we should also set a new value to one * of the controls */ int get_action(int sock, struct video_device *d) { int c, ctrl_index = 0, value = 0, ret = ACTION_CAPTURE; char *buf, *sptr, *fptr; struct control_list *l = get_control_list(d); XMALLOC(buf, char *, INPUT_BLOCK_SIZE); c = read(sock, buf, INPUT_BLOCK_SIZE - 1); buf[c] = '\0'; if(strstr(buf, "webcam") != NULL) { ret = ACTION_CAPTURE; info(LOG_INFO, "going for capture\n"); } else if (strstr(buf, "list") != NULL){ ret = ACTION_LIST; if((sptr = strstr(buf, "?")) != NULL) { fptr = strstr(sptr, " HTTP"); *fptr = '\0'; if(sscanf(++sptr, "val=%6d&%3d=update", &value, &ctrl_index) == 2) { //catch the jpeg control setting if(ctrl_index==-1) { info(LOG_INFO, "Setting JPEG quality to %d\n", value); if((1 <= value) && (value <= 100)) jpeg_quality=value; else info(LOG_ERR, "Invalid jpeg quality value %d\n", value); } else if(ctrl_index==-2) { //catch the frame ratio control info(LOG_INFO, "Setting frame ratio to %d\n", value); if((1 <= value) && (value <= 25)) { requested_fps = value; set_fps(requested_fps); } else info(LOG_ERR, "Invalid frame rate %d\n", value); } else { assert(ctrl_index < l->count); info(LOG_INFO, "Setting %s to %d\n", l->controls[ctrl_index].v4l2_ctrl->name, value); set_control_value(d, l->controls[ctrl_index].v4l2_ctrl, &value); info(LOG_INFO, "New value: %d\n", value); } } else info(LOG_ERR, "Error parsing URL. Unable to set new value\n"); } } XFREE(buf); release_control_list(d); return ret; }
/* * Init the control interface - Creates a list of controls */ JNIEXPORT jobjectArray JNICALL Java_au_edu_jcu_v4l4j_VideoDevice_doGetControlList(JNIEnv *e, jobject t, jlong object){ dprint(LOG_CALLS, "[CALL] Entering %s\n",__PRETTY_FUNCTION__); struct v4l4j_device *d = (struct v4l4j_device *) (uintptr_t) object; struct control_list *l; jclass v4l2ControlClass; jmethodID ctor; jobjectArray ctrls, names_array; jintArray values_array; jobject element; int i, type; dprint(LOG_LIBVIDEO, "[LIBVIDEO] Calling get_control_list()\n"); l = get_control_list(d->vdev); //Creates the java objects matching v4l2 controls dprint(LOG_V4L4J, "[V4L4J] Creating the Control array[%d]\n", l->count); v4l2ControlClass = (*e)->FindClass(e,CONTROL_CLASS); if(v4l2ControlClass == NULL){ info("[V4L4J] Error looking up the Control class\n"); release_control_list(d->vdev); THROW_EXCEPTION(e, JNI_EXCP, "Error looking up Control class"); return 0; } ctor = (*e)->GetMethodID(e, v4l2ControlClass, "<init>", "(ILjava/lang/String;IIII[Ljava/lang/String;[IJ)V"); if(ctor == NULL){ info("[V4L4J] Error looking up the Control class constructor\n"); release_control_list(d->vdev); THROW_EXCEPTION(e, JNI_EXCP, "Error looking up Control class constructor"); return 0; } //initialise the ctrls field of FrameGrabber object (this) ctrls = (*e)->NewObjectArray(e, l->count, v4l2ControlClass, NULL); if(ctrls == NULL){ info("[V4L4J] Error creating the control array\n"); release_control_list(d->vdev); THROW_EXCEPTION(e, JNI_EXCP, "Error creating the control array"); return 0; } //Construct a V4L2Control Java object for each V4L2control in l for(i = 0; i< l->count; i++) { if(l->controls[i].count_menu==0) { values_array = NULL; names_array = NULL; } else { //create the values and names arrays if((values_array = get_values(e,&l->controls[i])) == NULL) { release_control_list(d->vdev); return 0; } if((names_array = get_names(e,&l->controls[i])) ==NULL){ release_control_list(d->vdev); return 0; } } if((type = translate_type(e, l->controls[i].v4l2_ctrl->type))==-1) return 0; dprint(LOG_V4L4J, "[V4L4J] Creating Control %d - name: %s - type: %d\n", i, l->controls[i].v4l2_ctrl->name, type); element = (*e)->NewObject(e, v4l2ControlClass, ctor, i,\ (*e)->NewStringUTF(e, (const char *)l->controls[i].v4l2_ctrl->name),\ l->controls[i].v4l2_ctrl->minimum, l->controls[i].v4l2_ctrl->maximum, \ l->controls[i].v4l2_ctrl->step, type, names_array, values_array, object); if(element == NULL){ info("[V4L4J] Error creating the control '%s'\n", l->controls[i].v4l2_ctrl->name); release_control_list(d->vdev); THROW_EXCEPTION(e, JNI_EXCP, "Error creating the control '%s'", l->controls[i].v4l2_ctrl->name); return 0; } (*e)->SetObjectArrayElement(e, ctrls, i, element); } return ctrls; }
int main(int argc, char** argv) { struct capture_device *c; struct control_list *l; struct v4l2_queryctrl *qc; struct video_device *v; int std=0, channel=0, i, j; if(argc!=2 && argc!=4) { printf("This program requires the path to the video device file to be tested.\n"); printf("The optional second and third arguments are a video standard and channel.\n"); printf("Usage: %s <video_device_file> [standard channel]\n", argv[0]); printf("Video standards: webcam:0 - PAL:1 - SECAM:2 - NTSC:3\n"); return -1; } if (argc==4){ std = atoi(argv[2]); channel = atoi(argv[3]); printf("Using standard %d, channel %d\n",std, channel); } v = open_device(argv[1]); if(v==NULL){ printf("Error opening device\n"); return -1; } c = init_capture_device(v,MAX_WIDTH,MAX_HEIGHT,channel,std,3); c->actions->list_cap(v->fd); free_capture_device(v); l = get_control_list(v); printf("Listing available controls (%d)\n", l->count); for(i=0;i<l->count; i++){ qc = l->controls[i].v4l2_ctrl; printf("Control: id: 0x%x - name: %s - min: %d -max: %d - step: %d - type: %d(%s) - flags: %d (%s%s%s%s%s%s)\n", qc->id, (char *) &qc->name, qc->minimum, qc->maximum, qc->step, qc->type, qc->type == V4L2_CTRL_TYPE_INTEGER ? "Integer" : qc->type == V4L2_CTRL_TYPE_BOOLEAN ? "Boolean" : qc->type == V4L2_CTRL_TYPE_MENU ? "Menu" : qc->type == V4L2_CTRL_TYPE_BUTTON ? "Button" : qc->type == V4L2_CTRL_TYPE_INTEGER64 ? "Integer64" : qc->type == V4L2_CTRL_TYPE_CTRL_CLASS ? "Class" : qc->type == V4L2_CTRL_TYPE_STRING ? "String" : qc->type == V4L2_CTRL_TYPE_BITMASK ? "Bitmask" : "", qc->flags, qc->flags & V4L2_CTRL_FLAG_DISABLED ? "Disabled " : "", qc->flags & V4L2_CTRL_FLAG_GRABBED ? "Grabbed " : "", qc->flags & V4L2_CTRL_FLAG_READ_ONLY ? "ReadOnly " : "", qc->flags & V4L2_CTRL_FLAG_UPDATE ? "Update " : "", qc->flags & V4L2_CTRL_FLAG_INACTIVE ? "Inactive " : "", qc->flags & V4L2_CTRL_FLAG_SLIDER ? "slider " : "", qc->flags & V4L2_CTRL_FLAG_WRITE_ONLY ? "Write only" : ""); if(l->controls[i].count_menu!=0){ printf("Menu items (%d) %s\n", l->controls[i].count_menu, l->controls[i].v4l2_ctrl->step==1?"contiguous":"non-contiguous"); for(j=0; j<l->controls[i].count_menu; j++) printf("\tMenu item: %s - %d\n", l->controls[i].v4l2_menu[j].name, l->controls[i].v4l2_menu[j].index); } } get_device_info(v); print_device_info(v); release_device_info(v); release_control_list(v); close_device(v); return 0; }