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
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
/* * 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); }