Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info. |
Ij.c
Jump to navigation
Jump to search
/* * ij.c - device-independent input jacks for VL * * WARNING this version has not been tested for all jacks for * all devices. */ #include "ij.h" #include <stdio.h> #include <stdlib.h> #include <assert.h> /* devices ------------------------------------------------------------- */ typedef struct ijdevice { int (*setup)(IJhandle me, VLNode drain_node); /* returns TRUE on success */ char *(*getjackname)(IJhandle me, int idx); int (*getdefaultsource)(IJhandle me); int (*mapidx)(IJhandle me, int idx, int *ret_idx_base); int (*configurepath)(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx); /*returns 0 on success*/ int (*isjackcontrol)(IJhandle me, VLControlType type); void (*teardown)(IJhandle me); } ijdevice; /* handle ------------------------------------------------------------- */ typedef struct _IJhandle { VLServer svr; VLDevList devlist; VLDev device; ijdevice *ijd; void *dev_specific; int num_jacks; char *device_name; } _IJhandle; /* util ------------------------------------------------------------- */ /* * get video source node number of the device's default source */ int getdefaultsource(IJhandle me) { VLNode devNode; VLPath controlPath; VLControlValue val; val.intVal = -1; if (-1 != (devNode = vlGetNode(me->svr, VL_DEVICE, 0, VL_ANY)) && -1 != (controlPath = vlCreatePath(me->svr, me->device, devNode, devNode))&& -1 != vlSetupPaths(me->svr, &controlPath, 1, VL_SHARE, VL_READ_ONLY) && -1 != vlGetControl(me->svr, controlPath, devNode, VL_DEFAULT_SOURCE, &val) && -1 != vlDestroyPath(me->svr, controlPath)) return val.intVal; return -1; } /* vino ------------------------------------------------------------- */ int vinosetup(IJhandle me, VLNode drain_node) { me->num_jacks = 3; me->device_name = "VINO Video"; return TRUE; } char *vinogetjackname(IJhandle me, int idx) { switch (idx) { case 0: return "Composite"; case 1: return "S-Video"; case 2: return "Indycam/601 Serial Digital"; default: return NULL; } } #define VINO_ANALOG_NODE 1 #define VINO_DIGITAL_NODE 0 #define VINO_COMPOSITE_MUXSWITCH 0 #define VINO_SVIDEO_MUXSWITCH 1 /* map idx to node number. idx is between 0 and me->num_jacks-1. */ int vinomapidx(IJhandle me, int idx, int *ret_idx_base) { int node_number; switch (idx) { case 0: case 1: node_number = VINO_ANALOG_NODE; break; case 2: node_number = VINO_DIGITAL_NODE; break; default: return -1; } if (ret_idx_base) *ret_idx_base = 0; /* not used for vino */ return node_number; } int vinoconfigurepath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { VLControlValue val; int returned_idx; /* -- perform node-number-specific operations */ switch (node_number) { case VINO_ANALOG_NODE: { if (idx==VL_ANY) { if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } switch (val.intVal) { case VINO_COMPOSITE_MUXSWITCH: returned_idx = 0; break; case VINO_SVIDEO_MUXSWITCH: returned_idx = 1; break; } } else { returned_idx = idx; switch (idx) { case 0: val.intVal = VINO_COMPOSITE_MUXSWITCH; break; case 1: val.intVal = VINO_SVIDEO_MUXSWITCH; break; } if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } } break; case VINO_DIGITAL_NODE: { /* XXX need to set VL_TIMING differently for 601 option? */ returned_idx = 2; } break; } if (ret_idx) *ret_idx = returned_idx; return 0; } int vinoisjackcontrol(IJhandle me, VLControlType type) { return (type==VL_MUXSWITCH)||(type==VL_FORMAT); } ijdevice vinodev = { vinosetup, vinogetjackname, NULL, vinomapidx, vinoconfigurepath, vinoisjackcontrol, NULL }; /* ev1 ------------------------------------------------------------- */ /* junior and on-board have 3 analog jacks, ABOB has 8 jacks */ #define JUNIOR_ANALOG 3 #define ABOB_ANALOG 8 /* DBOB has 2 jacks that we support. we don't support serial or * parallel digital in 2 because it is often not accessible * if the user happens to have a cosmo1 board also plugged in--it's * not worth the documentation/usability nightmare. */ #define DBOB 2 #define NO_DBOB 0 /* indycam plugs into the same place as DBOB and acts as one input */ #define INDYCAM 1 #define NO_INDYCAM 0 typedef struct ev1data { int num_analog_jacks; /* JUNIOR_ANALOG or ABOB_ANALOG */ int num_dbob_jacks; /* DBOB or NO_DBOB */ int num_indycam_jacks; /* INDYCAM or NO_INDYCAM */ int analog_base; int dbob_base; int indycam_base; } ev1data; #include <invent.h> #include <dmedia/vl_ev1.h> int ev1setup(IJhandle me, VLNode drain_node) { ev1data *ev1 = me->dev_specific = malloc(sizeof(ev1data)); inventory_t cpu, vid; inv_state_t *foo = NULL; inventory_t *inv; if (!ev1) return FALSE; cpu.inv_class = -1; vid.inv_class = -1; /* search for CPU and video in inventory */ if (setinvent_r(&foo) < 0) return FALSE; while ((inv = getinvent_r(foo)) && (vid.inv_class == -1 || cpu.inv_class == -1)) { if (inv->inv_class == INV_VIDEO && (inv->inv_type == INV_VIDEO_EXPRESS || inv->inv_type == INV_VIDEO_INDY || inv->inv_type == INV_VIDEO_INDY_601)) vid = *inv; else if (inv->inv_class == INV_PROCESSOR && inv->inv_type == INV_CPUBOARD) cpu = *inv; } endinvent_r(foo); if (vid.inv_class == -1 || cpu.inv_class == -1) { free(ev1); me->dev_specific = NULL; return FALSE; } if (vid.inv_type == INV_VIDEO_INDY) { /* Indy Video */ ev1->num_analog_jacks = JUNIOR_ANALOG; ev1->num_dbob_jacks = NO_DBOB; ev1->num_indycam_jacks = NO_INDYCAM; me->device_name = "Indy Video"; } else if (vid.inv_type == INV_VIDEO_INDY_601) { /* Indy Video 601 */ ev1->num_analog_jacks = JUNIOR_ANALOG; /* vid.inv_state & INV_GALILEO_DBOB is not set for Indy Video 601 */ ev1->num_dbob_jacks = DBOB; ev1->num_indycam_jacks = NO_INDYCAM; me->device_name = "Indy Video 601"; } else if (vid.inv_type == INV_VIDEO_EXPRESS) { /* an Indigo or Indigo2 ev1 */ if (cpu.inv_state == INV_IP12BOARD || cpu.inv_state == INV_IP20BOARD) { /* Indigo Video */ ev1->num_analog_jacks = ABOB_ANALOG; if (vid.inv_state & INV_GALILEO_DBOB) ev1->num_dbob_jacks = DBOB; if (vid.inv_state & INV_GALILEO_INDY_CAM) ev1->num_indycam_jacks = INDYCAM; me->device_name = "Indigo Video"; } else { /* an Indigo2 board */ if (vid.inv_state & INV_GALILEO_JUNIOR) { /* a junior board -- Indigo2 Video * or Indigo2 Video for Impact */ ev1->num_analog_jacks = JUNIOR_ANALOG; ev1->num_dbob_jacks = NO_DBOB; if (vid.inv_state & INV_GALILEO_INDY_CAM) ev1->num_indycam_jacks = INDYCAM; me->device_name = "Indigo2 Video"; } else { /* Galileo Video */ ev1->num_analog_jacks = ABOB_ANALOG; if (vid.inv_state & INV_GALILEO_DBOB) ev1->num_dbob_jacks = DBOB; if (vid.inv_state & INV_GALILEO_INDY_CAM) ev1->num_indycam_jacks = INDYCAM; me->device_name = "Galileo Video"; } } } else /* video not found, or unrecognized ev1 board */ return FALSE; me->num_jacks = ev1->num_analog_jacks + ev1->num_dbob_jacks + ev1->num_indycam_jacks; ev1->analog_base = 0; ev1->dbob_base = ev1->num_analog_jacks; ev1->indycam_base = ev1->num_analog_jacks + ev1->num_dbob_jacks; return TRUE; } char *ev1getjackname(IJhandle me, int idx) { ev1data *ev1 = me->dev_specific; if (idx+ev1->analog_base < ev1->num_analog_jacks) { idx -= ev1->analog_base; /* analog jack */ if (ev1->num_analog_jacks == ABOB_ANALOG) switch (idx) { case 0: return "Composite 1"; case 1: return "Composite 2"; case 2: return "Composite 3"; case 3: return "S-Video (Y/C) 1"; case 4: return "S-Video (Y/C) 2"; case 5: return "S-Video (Y/C) 3"; case 6: return "Component (Y, R-Y, B-Y) 1"; case 7: return "Component (Y, R-Y, B-Y) 2"; } else /* JUNIOR_ANALOG */ switch (idx) { case 0: return "Composite 1"; case 1: return "Composite 2"; case 2: return "S-Video"; } return NULL; } if (idx-ev1->dbob_base < ev1->num_dbob_jacks) { idx -= ev1->dbob_base; /* digital jack */ switch (idx) { case 0: return "601 Serial Digital 1"; case 1: return "601 Parallel Digital 1"; } return NULL; } if (idx-ev1->indycam_base < ev1->num_indycam_jacks) { idx -= ev1->indycam_base; return "IndyCam"; } return NULL; } #define EV1_ANALOG_NODE 0 #define EV1_DIGITAL1_NODE 1 #define EV1_ABOB_COMPOSITE1_MUXSWITCH 3 #define EV1_ABOB_COMPOSITE2_MUXSWITCH 4 #define EV1_ABOB_COMPOSITE3_MUXSWITCH 5 #define EV1_ABOB_YC1_MUXSWITCH 0 #define EV1_ABOB_YC2_MUXSWITCH 1 #define EV1_ABOB_YC3_MUXSWITCH 2 #define EV1_ABOB_COMPONENT1_MUXSWITCH 6 #define EV1_ABOB_COMPONENT2_MUXSWITCH 7 #define EV1_JUNIOR_COMPOSITE1_MUXSWITCH 3 #define EV1_JUNIOR_COMPOSITE2_MUXSWITCH 4 #define EV1_JUNIOR_YC1_MUXSWITCH 1 #define EV1_DBOB_SERIAL_DIGITAL 1 #define EV1_DBOB_PARALLEL_DIGITAL 0 /* map idx to node number. idx is between 0 and me->num_jacks-1. */ int ev1mapidx(IJhandle me, int idx, int *ret_idx_base) { int node_number; int idx_base; ev1data *ev1 = me->dev_specific; if (idx-ev1->analog_base < ev1->num_analog_jacks) { idx_base = ev1->analog_base; node_number = EV1_ANALOG_NODE; } else if (idx-ev1->dbob_base < ev1->num_dbob_jacks) { idx_base = ev1->dbob_base; node_number = EV1_DIGITAL1_NODE; } else if (idx-ev1->indycam_base < ev1->num_indycam_jacks) { idx_base = ev1->indycam_base; node_number = EV1_DIGITAL1_NODE; } else return -1; if (ret_idx_base) *ret_idx_base = idx_base; return node_number; } int ev1configurepath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { VLControlValue val; int returned_idx; int idx_base=-1; ev1data *ev1 = me->dev_specific; /* -- compute idx_base if idx != VL_ANY */ if (idx != VL_ANY) { node_number = ev1mapidx(me, idx, &idx_base); assert(node_number >= 0); assert(idx_base >= 0); idx -= idx_base; } /* -- perform node-number-specific operations */ switch (node_number) { case EV1_ANALOG_NODE: if (idx == VL_ANY) { idx_base = ev1->analog_base; if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } if (ev1->num_analog_jacks == ABOB_ANALOG) switch (val.intVal) { case EV1_ABOB_COMPOSITE1_MUXSWITCH: returned_idx = 0; break; case EV1_ABOB_COMPOSITE2_MUXSWITCH: returned_idx = 1; break; case EV1_ABOB_COMPOSITE3_MUXSWITCH: returned_idx = 2; break; case EV1_ABOB_YC1_MUXSWITCH: returned_idx = 3; break; case EV1_ABOB_YC2_MUXSWITCH: returned_idx = 4; break; case EV1_ABOB_YC3_MUXSWITCH: returned_idx = 5; break; case EV1_ABOB_COMPONENT1_MUXSWITCH: returned_idx = 6; break; case EV1_ABOB_COMPONENT2_MUXSWITCH: returned_idx = 7; break; } else /* JUNIOR_ANALOG */ switch (val.intVal) { case EV1_JUNIOR_COMPOSITE1_MUXSWITCH: returned_idx = 0; break; case EV1_JUNIOR_COMPOSITE2_MUXSWITCH: returned_idx = 1; break; case EV1_JUNIOR_YC1_MUXSWITCH: returned_idx = 2; break; } } else { returned_idx = idx; if (ev1->num_analog_jacks == ABOB_ANALOG) switch (idx) { case 0: val.intVal = EV1_ABOB_COMPOSITE1_MUXSWITCH; break; case 1: val.intVal = EV1_ABOB_COMPOSITE2_MUXSWITCH; break; case 2: val.intVal = EV1_ABOB_COMPOSITE3_MUXSWITCH; break; case 3: val.intVal = EV1_ABOB_YC1_MUXSWITCH; break; case 4: val.intVal = EV1_ABOB_YC2_MUXSWITCH; break; case 5: val.intVal = EV1_ABOB_YC3_MUXSWITCH; break; case 6: val.intVal = EV1_ABOB_COMPONENT1_MUXSWITCH; break; case 7: val.intVal = EV1_ABOB_COMPONENT2_MUXSWITCH; break; } else /* JUNIOR_ANALOG */ switch (idx) { case 0: val.intVal = EV1_JUNIOR_COMPOSITE1_MUXSWITCH; break; case 1: val.intVal = EV1_JUNIOR_COMPOSITE2_MUXSWITCH; break; case 2: val.intVal = EV1_JUNIOR_YC1_MUXSWITCH; break; } if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } break; case EV1_DIGITAL1_NODE: /* indycam or dbob (not both) */ if (idx == VL_ANY) { if (ev1->num_indycam_jacks == INDYCAM) { idx_base = ev1->indycam_base; returned_idx = 0; } else { idx_base = ev1->dbob_base; if (vlGetControl(me->svr, path, source_node, VL_EV1_DBOB_INPUT1, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } switch (val.intVal) { case EV1_DBOB_SERIAL_DIGITAL: returned_idx = 0; break; case EV1_DBOB_PARALLEL_DIGITAL: returned_idx = 1; break; } } } else { returned_idx = idx; /* XXX need to set VL_EV1_DBOB_INPUT1 for indycam? */ if (ev1->num_indycam_jacks == NO_INDYCAM) { switch (idx) { case 0: val.intVal = EV1_DBOB_SERIAL_DIGITAL; break; case 1: val.intVal = EV1_DBOB_PARALLEL_DIGITAL; break; } if (vlSetControl(me->svr, path, source_node, VL_EV1_DBOB_INPUT1, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } } break; } assert(idx_base != -1); if (ret_idx) *ret_idx = returned_idx + idx_base; return 0; } int ev1isjackcontrol(IJhandle me, VLControlType type) { return (type==VL_MUXSWITCH); } void ev1teardown(IJhandle me) { ev1data *ev1 = me->dev_specific; free(ev1); me->dev_specific = NULL; } ijdevice ev1dev = { ev1setup, ev1getjackname, NULL, ev1mapidx, ev1configurepath, ev1isjackcontrol, ev1teardown }; /* impact ------------------------------------------------------------- */ /* * "impact" is a single VL device that, underneath, could be: * - Impact Video only * - Impact Compression only * - Impact Video and Impact Compression together * * Impact Video will show up as input node numbers 0, 1, and 2, * and Impact Compression will show up as input node number 4. */ #define NO_EV3 0 #define EV3 3 #define NO_COSMO2 0 #define COSMO2 2 typedef struct impactdata { int num_ev3_jacks; /* Impact Video jacks: NO_EV3 or EV3 */ int num_cosmo2_jacks; /* Impact Compression jacks: NO_COSMO2 or COSMO2 */ int ev3_base; int cosmo2_base; } impactdata; int impactsetup(IJhandle me, VLNode drain_node) { int dv, nd; impactdata *iv = me->dev_specific = malloc(sizeof(impactdata)); for (dv=0; dv < (int)me->devlist.numDevices; dv++) if (me->devlist.devices[dv].dev == me->device) break; assert(dv != (int)me->devlist.numDevices); iv->num_ev3_jacks = NO_EV3; iv->num_cosmo2_jacks = NO_COSMO2; for(nd=0; nd < me->devlist.devices[dv].numNodes; nd++) { int node_number = me->devlist.devices[dv].nodes[nd].number; if (node_number == 0) /* one of ev3's nodes */ iv->num_ev3_jacks = EV3; else if (node_number == 4) /* one of cosmo2's nodes */ iv->num_cosmo2_jacks = COSMO2; } me->num_jacks = iv->num_ev3_jacks + iv->num_cosmo2_jacks; iv->ev3_base = 0; iv->cosmo2_base = iv->num_ev3_jacks; /* one or the other must be there!! */ assert(iv->num_ev3_jacks==EV3 || iv->num_cosmo2_jacks==COSMO2); if (iv->num_ev3_jacks==EV3 && iv->num_cosmo2_jacks==NO_COSMO2) me->device_name = "Impact Video"; else if (iv->num_ev3_jacks==NO_EV3 && iv->num_cosmo2_jacks==COSMO2) me->device_name = "Impact Compression"; else me->device_name = "Impact Video/Impact Compression"; return TRUE; } char *impactgetjackname(IJhandle me, int idx) { impactdata *iv = me->dev_specific; if (idx-iv->ev3_base < iv->num_ev3_jacks) { idx -= iv->ev3_base; switch (idx) { case 0: return "601 Serial Digital 1"; case 1: return "601 Serial Digital 2"; case 2: return "601 Serial Digital Dual-Link"; } return NULL; } if (idx-iv->cosmo2_base < iv->num_cosmo2_jacks) { idx -= iv->cosmo2_base; switch (idx) { case 0: return "Composite"; case 1: return "S-Video"; } return NULL; } return NULL; } #define IMPACT_SERIAL1_NODE 0 #define IMPACT_SERIAL2_NODE 1 #define IMPACT_DUAL_LINK_NODE 2 #define IMPACT_COSMO2_NODE 4 #define IMPACT_COMPOSITE_MUXSWITCH 0 #define IMPACT_SVIDEO_MUXSWITCH 1 /* map idx to node number. idx is between 0 and me->num_jacks-1. */ int impactmapidx(IJhandle me, int idx, int *ret_idx_base) { int node_number; int idx_base; impactdata *iv = me->dev_specific; if (idx-iv->ev3_base < iv->num_ev3_jacks) { idx_base = iv->ev3_base; idx -= idx_base; switch (idx) { case 0: node_number = IMPACT_SERIAL1_NODE; break; case 1: node_number = IMPACT_SERIAL2_NODE; break; case 2: node_number = IMPACT_DUAL_LINK_NODE; break; } } else if (idx-iv->cosmo2_base < iv->num_cosmo2_jacks) { idx_base = iv->cosmo2_base; node_number = IMPACT_COSMO2_NODE; } else return -1; if (ret_idx_base) *ret_idx_base = idx_base; return node_number; } int impactconfigurepath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { VLControlValue val; int returned_idx; int idx_base=-1; impactdata *iv = me->dev_specific; /* -- compute idx_base if idx != VL_ANY */ if (idx != VL_ANY) { node_number = impactmapidx(me, idx, &idx_base); assert(node_number >= 0); assert(idx_base >= 0); idx -= idx_base; } /* -- perform node-number-specific operations */ switch (node_number) { case IMPACT_SERIAL1_NODE: idx_base = iv->ev3_base; returned_idx = 0; break; case IMPACT_SERIAL2_NODE: idx_base = iv->ev3_base; returned_idx = 1; break; case IMPACT_DUAL_LINK_NODE: idx_base = iv->ev3_base; returned_idx = 2; break; case IMPACT_COSMO2_NODE: if (idx == VL_ANY) { idx_base = iv->cosmo2_base; if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } switch (val.intVal) { case IMPACT_COMPOSITE_MUXSWITCH: returned_idx = 0; break; case IMPACT_SVIDEO_MUXSWITCH: returned_idx = 1; break; } } else { returned_idx = idx; switch (idx) { case 0: val.intVal = IMPACT_COMPOSITE_MUXSWITCH; break; case 1: val.intVal = IMPACT_SVIDEO_MUXSWITCH; break; } if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } break; } assert(idx_base != -1); if (ret_idx) *ret_idx = returned_idx + idx_base; return 0; } int impactisjackcontrol(IJhandle me, VLControlType type) { return (type==VL_MUXSWITCH); } void impactteardown(IJhandle me) { impactdata *iv = me->dev_specific; free(iv); me->dev_specific = NULL; } ijdevice impactdev = { impactsetup, impactgetjackname, NULL, impactmapidx, impactconfigurepath, impactisjackcontrol, impactteardown }; /* sirius ------------------------------------------------------------- */ int siriussetup(IJhandle me, VLNode drain_node) { /* probe for serial digital i/o option */ VLControlInfo *info; int i; VLNode node = vlGetNode(me->svr, VL_SRC, VL_VIDEO, 0 /* digital in 1 */ ); VLPath path = vlCreatePath(me->svr, me->device, node, drain_node); if (node < 0 || path < 0) return FALSE; /* argh! have to set up path for vlGetControlInfo to work! */ if (vlSetupPaths(me->svr, (VLPathList)&path, 1, VL_READ_ONLY, VL_READ_ONLY) < 0) { vlDestroyPath(me->svr, path); return FALSE; } /* search the VL_FORMAT parameter for any serial digital setting */ info = vlGetControlInfo(me->svr, path, node, VL_FORMAT); if (!info) { vlDestroyPath(me->svr, path); return FALSE; } for(i=0; i < info->numItems; i++) if (info->itemList[i].value == 8 /* serial 4:2:2:4 */) break; if (i == info->numItems) me->num_jacks = 10; /* no serial digital at all */ else me->num_jacks = 14; /* full serial digital (single/dual, 1/2) */ me->device_name = "Sirius Video"; if (vlFreeControlInfo(me->svr, info) < 0) { vlDestroyPath(me->svr, path); return FALSE; } if (vlDestroyPath(me->svr, path) < 0) return FALSE; return TRUE; } char *siriusgetjackname(IJhandle me, int idx) { switch (idx) { case 0: return "RGB"; case 1: return "YUV"; case 2: return "Betacam"; case 3: return "M-II"; case 4: return "Composite"; case 5: return "S-Video"; case 6: return "601 Parallel Digital 1: 4:2:2:4"; case 7: return "601 Parallel Digital 2: 4:2:2:4"; case 8: return "601 Parallel Digital 1: 4:4:4:4"; case 9: return "601 Parallel Digital 2: 4:4:4:4"; case 10: return "601 Serial Digital 1: 4:2:2:4"; case 11: return "601 Serial Digital 2: 4:2:2:4"; case 12: return "601 Serial Digital 1: 4:4:4:4"; case 13: return "601 Serial Digital 2: 4:4:4:4"; } } #define SIRIUS_DIGITAL1_NODE 0 #define SIRIUS_DIGITAL2_NODE 1 #define SIRIUS_ANALOG_NODE 2 /* map idx to node number. idx is between 0 and me->num_jacks-1. */ int siriusmapidx(IJhandle me, int idx, int *ret_idx_base) { int node_number; int idx_base; if (idx < 6) /* analog jack */ { idx_base = 0; node_number = SIRIUS_ANALOG_NODE; } else /* digital jack */ { idx_base = 6; idx -= idx_base; node_number = (idx % 2 == 0) ? SIRIUS_DIGITAL1_NODE : SIRIUS_DIGITAL2_NODE; } if (ret_idx_base) *ret_idx_base = idx_base; return node_number; } int siriusconfigurepath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { VLControlValue val; int returned_idx; int idx_base=-1; /* -- compute idx_base if idx != VL_ANY */ if (idx != VL_ANY) { node_number = siriusmapidx(me, idx, &idx_base); assert(node_number >= 0); assert(idx_base >= 0); idx -= idx_base; } /* -- perform node-number-specific operations */ switch (node_number) { case SIRIUS_DIGITAL1_NODE: case SIRIUS_DIGITAL2_NODE: if (idx == VL_ANY) { idx_base = 6; if (vlGetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } switch (val.intVal) { case VL_FORMAT_DIGITAL_COMPONENT: returned_idx=0; break; case VL_FORMAT_DIGITAL_COMPONENT_DUAL: returned_idx=2; break; case VL_FORMAT_DIGITAL_COMPONENT_SERIAL: returned_idx=4; break; case VL_FORMAT_DIGITAL_COMPONENT_DUAL_SERIAL: returned_idx=6; break; } if (node_number == SIRIUS_DIGITAL2_NODE) returned_idx += 1; } else { returned_idx = idx; if (idx == 0 || idx == 1) /* parallel 4:2:2:4 */ val.intVal = VL_FORMAT_DIGITAL_COMPONENT; if (idx == 2 || idx == 3) /* parallel 4:4:4:4 */ val.intVal = VL_FORMAT_DIGITAL_COMPONENT_DUAL; if (idx == 4 || idx == 5) /* serial 4:2:2:4 */ val.intVal = VL_FORMAT_DIGITAL_COMPONENT_SERIAL; if (idx == 6 || idx == 7) /* serial 4:4:4:4 */ val.intVal = VL_FORMAT_DIGITAL_COMPONENT_DUAL_SERIAL; if (vlSetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } break; case SIRIUS_ANALOG_NODE: if (idx == VL_ANY) { idx_base = 0; if (vlGetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } switch (val.intVal) { case VL_FORMAT_RGB: returned_idx = 0; break; case VL_FORMAT_SMPTE_YUV: returned_idx = 1; break; case VL_FORMAT_BETACAM: returned_idx = 2; break; case VL_FORMAT_MII: returned_idx = 3; break; case VL_FORMAT_COMPOSITE: returned_idx = 4; break; case VL_FORMAT_SVIDEO: returned_idx = 5; break; } } else { returned_idx = idx; switch (idx) { case 0: val.intVal = VL_FORMAT_RGB; break; case 1: val.intVal = VL_FORMAT_SMPTE_YUV; break; case 2: val.intVal = VL_FORMAT_BETACAM; break; case 3: val.intVal = VL_FORMAT_MII; break; case 4: val.intVal = VL_FORMAT_COMPOSITE; break; case 5: val.intVal = VL_FORMAT_SVIDEO; break; } if (vlSetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0) { vlDestroyPath(me->svr, path); return -1; } } break; } assert(idx_base != -1); if (ret_idx) *ret_idx = returned_idx + idx_base; return 0; } int siriusisjackcontrol(IJhandle me, VLControlType type) { return (type==VL_FORMAT); } ijdevice siriusdev = { siriussetup, siriusgetjackname, NULL, siriusmapidx, siriusconfigurepath, siriusisjackcontrol, NULL }; /* mvp ------------------------------------------------------------- */ typedef struct mvpjack { char *name; int number; } mvpjack; typedef struct mvpdata { mvpjack *jacks; int camera_present; } mvpdata; /* this is actually defined in /usr/include/dmedia/vl_mvp.h, * but since that include file has only been shipped on IRIX 6.3, * and we want ij to be buildable on as many platforms as * possible, we do this. */ #define VL_MVP_VIDEO_SOURCE_CAMERA 1 int mvpsetup(IJhandle me, VLNode drain_node) { mvpdata *mvp = me->dev_specific = malloc(sizeof(mvpdata)); int i,j; if (!mvp) return FALSE; me->device_name = "O2 Video"; me->num_jacks = 0; /* count the video input jacks and look for the camera. * * for some reason, if the camera node is present, the digital node * is always also present, even though the driver knows full well that * the camera is plugged in and not the digital dongle. so if we see * the camera node, we will not use the digital node. */ mvp->camera_present = 0; for (i = 0; i < me->devlist.devices[me->device].numNodes; i++) { if ((me->devlist.devices[me->device].nodes[i].type == VL_SRC) && (me->devlist.devices[me->device].nodes[i].kind == VL_VIDEO)) { me->num_jacks++; if (me->devlist.devices[me->device].nodes[i].number == VL_MVP_VIDEO_SOURCE_CAMERA) mvp->camera_present = 1; } } mvp->jacks = malloc(sizeof(mvpjack) * me->num_jacks); /* proceed through list again querying each jack, * and skipping the digital node if the camera is present. */ j = 0; for (i = 0; i < me->devlist.devices[me->device].numNodes; i++) { if ((me->devlist.devices[me->device].nodes[i].type == VL_SRC) && (me->devlist.devices[me->device].nodes[i].kind == VL_VIDEO)) { mvp->jacks[j].name = me->devlist.devices[me->device].nodes[i].name; mvp->jacks[j].number = me->devlist.devices[me->device].nodes[i].number; /* see above for this hack */ if (mvp->camera_present && !strcmp(mvp->jacks[j].name, "Digital Video Input")) continue; /* fixup some lame names */ if (!strcmp(mvp->jacks[j].name, "Loopback E Video Input")) mvp->jacks[j].name = "Video Output Looped Back to Input"; else if (!strcmp(mvp->jacks[j].name, "Loopback F Video Input")) mvp->jacks[j].name = "Alpha Video Output Loopped Back to Input"; j++; } } me->num_jacks = j; return TRUE; } char *mvpgetjackname(IJhandle me, int idx) { mvpdata *mvp = me->dev_specific; return mvp->jacks[idx].name; } int mvpgetdefaultsource(IJhandle me) { mvpdata *mvp = me->dev_specific; int node_number = getdefaultsource(me); /* mvp sometimes returns the camera node as the default * source node even though it's not really available. * this is because the mvp driver detects no camera and * so doesn't include it in the node list, but when vcp * starts up and reads the saved system defaults, it * just blindly uses the saved value for default input * source, even if that source is no longer available. * * work around this by choosing a node that is available * if this situation comes up. * * XXX we should probably also set the default source * on the device node so that vcp gets out of this bad * state. */ if (node_number == VL_MVP_VIDEO_SOURCE_CAMERA && !mvp->camera_present) node_number = mvp->jacks[0].number; } /* map idx to node number. idx is between 0 and me->num_jacks-1. */ int mvpmapidx(IJhandle me, int idx, int *ret_idx_base) { mvpdata *mvp = me->dev_specific; return mvp->jacks[idx].number; } int mvpconfigurepath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { mvpdata *mvp = me->dev_specific; VLControlValue val; /* -- compute idx if idx == VL_ANY */ if (idx == VL_ANY) { for(idx=0; idx < me->num_jacks; idx++) if (mvp->jacks[idx].number = node_number) break; assert(idx < me->num_jacks); } if (ret_idx) *ret_idx = idx; return 0; } int mvpisjackcontrol(IJhandle me, VLControlType type) { return FALSE; } void mvpteardown(IJhandle me) { mvpdata *mvp = me->dev_specific; free(mvp->jacks); free(mvp); me->dev_specific = NULL; } ijdevice mvpdev = { mvpsetup, mvpgetjackname, mvpgetdefaultsource, mvpmapidx, mvpconfigurepath, mvpisjackcontrol, mvpteardown }; /* devicename ---------------------------------------------------------- */ ijdevice *vldevname_to_ijdevice(char *vl_device_name) { if (!strcmp(vl_device_name, "vino")) return &vinodev; else if (!strcmp(vl_device_name, "ev1")) return &ev1dev; else if (!strcmp(vl_device_name, "impact")) return &impactdev; else if (!strcmp(vl_device_name, "Sirius")) return &siriusdev; else if (!strcmp(vl_device_name, "mvp")) return &mvpdev; else return NULL; } /* API ------------------------------------------------------------- */ IJhandle ijOpenHandle(VLServer svr, VLDev device, VLNode drain_node) { IJhandle me = malloc(sizeof(_IJhandle)); if (!me) return NULL; me->svr = svr; me->device = device; /* --- get a specific device */ if (me->device == VL_ANY) { VLNode src_node; VLPath path; /* the VL is SO ANNOYING!! the only way to determine which device * would be used is to create an actual path! */ if ((src_node = vlGetNode(me->svr, VL_SRC, VL_VIDEO, VL_ANY)) < 0) { free(me); return NULL; } if ((path = vlCreatePath(me->svr, VL_ANY, src_node, drain_node)) < 0) { free(me); return NULL; } if (vlSetupPaths(me->svr, (VLPathList)&path, 1, VL_READ_ONLY, VL_READ_ONLY) < 0) { free(me); return NULL; } if ((me->device = vlGetDevice(me->svr, path)) < 0) { free(me); return NULL; } if (vlDestroyPath(me->svr, path) < 0) { free(me); return NULL; } } assert(me->device != VL_ANY); /* --- map VL device to IJ device */ me->ijd = NULL; { int dv; if (vlGetDeviceList(me->svr, &me->devlist) < 0) { free(me); return NULL; } for (dv=0; dv < (int)me->devlist.numDevices; dv++) { if (me->devlist.devices[dv].dev == me->device) { me->ijd = vldevname_to_ijdevice(me->devlist.devices[dv].name); break; } } } if (!me->ijd) { free(me); return NULL; } /* --- do device-specific setup (inventory etc.) */ me->num_jacks = -1; me->device_name = NULL; if (!(*me->ijd->setup)(me, drain_node)) /* this will set me->num_jacks */ { free(me); return NULL; } assert(me->num_jacks != -1); assert(me->device_name != NULL); return me; } void ijCloseHandle(IJhandle me) { if (me->ijd->teardown) (*me->ijd->teardown)(me); /* you are not supposed to free a VLDevList */ } char *ijGetDeviceName(IJhandle me) { return me->device_name; } int ijGetVLDev(IJhandle me) { return me->device; } int ijGetNumJacks(IJhandle me) { return me->num_jacks; } char *ijGetJackName(IJhandle me, int idx) { if (idx < 0 || idx >= me->num_jacks) return NULL; return (*me->ijd->getjackname)(me, idx); } int ijGetNodeNumber(IJhandle me, int idx) { int node_number; if (idx != VL_ANY && (idx < 0 || idx >= me->num_jacks)) return -1; /* -- map idx to node number, or find default node for idx==VL_ANY */ if (idx == VL_ANY) { if (me->ijd->getdefaultsource) node_number = (*me->ijd->getdefaultsource)(me); else node_number = getdefaultsource(me); } else node_number = (*me->ijd->mapidx)(me, idx, NULL); return node_number; } int ijConfigurePath(IJhandle me, int idx, VLNode source_node, VLNode drain_node, VLPath path, int node_number, int *ret_idx) { if (idx != VL_ANY && (idx < 0 || idx >= me->num_jacks)) return -1; if (node_number < 0) return -1; return (*me->ijd->configurepath)(me, idx, source_node, drain_node, path, node_number, ret_idx); } int ijDoesControlAffectInputJack(IJhandle me, VLControlType type) { return (*me->ijd->isjackcontrol)(me, type); }