Live video texturing on Onyx2 with DIVO

New Message Reply Date view Thread view Subject view Author view

Rochelle O'Hagan (rohagan++at++viswiz.gmd.de)
Wed, 18 Nov 1998 18:32:38 +0100


We are trying to get video texturing working on DIVO. We can't seem to
get the video image from dmBuffers into texture memory without linking
the texture to the video path directly. Any ideas?

The code follows:
Regards,
Rochelle O'Hagan

/*
 * fpDivoService.c++
 *
 * use the DIVO board of IR
 *
 * Copyright (c) 1998 GMD
 *
 *
 */

/*
#ifdef PF20
#define PFTEX_RGB_8 PFTEX_RGB_5
#endif
*/

#include <libfp/fpBasic.h>

#include <stdio.h>
#include <string.h>
#include <libgen.h>

#include <X11/X.h>
#include <X11/Xlib.h>

#include <Performer/pf.h>
#include <Performer/pfutil.h>
#include <Performer/pr.h>
#include <Performer/pr/pfTexture.h>
#include <Performer/pr/pfGeoSet.h>

// compile only on nessie
#ifdef COMPILE_ON_NESSIE
#include "fpDivoService.h"

#define PFNFY_DEBUG 1

#define CCIR_601_W 720
#define CCIR_601_H 576

#define SIR_W_RE2 768 // Sirius always transfers 768 pixels on
RE2
#define SIR_W_IR 720 // but 720 pixels on IR
#define SIR_H 576

// following are for PAL/625
// NTSC can use 1/2 H
//
#define TEX_W 1024
#define TEX_H_FRAME 1024
#define TEX_H_FIELD 512

DMbuffer _buff;
uint **dataPtr;

FP_BASE_DEFINE (fpDivoService)

fpDivoService::fpDivoService () :
    _vTexType (fpDivoParam::VTEX_RGBA),
    _divoState (fpDivoParam::FREE),
    _divoSource (fpDivoParam::ANY_SOURCE),
    _gfxType (fpDivoParam::GFX_OX_IR_DIVO)
{
    FP_BASE_FINISH_CONSTRUCT ();
}

fpDivoService::~fpDivoService ()
{
}

void
fpDivoService::initClass ()
{
  if (_classTypeId == fpType::badType ()) {
    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::initClass");

    FP_BASE_INIT (fpService, fpDivoService, TRUE, 0);

    // int scheme functions
    getClassTypeId ().registerMemberFunction ("init-divo", initDivoCB);
  }
}

// ----
// setting DIVO Source according to given input
// ANY_SOURCE would do since there is only one DIGITAL_SOURCE

int fpDivoService::initDivo (fpString DivoString)
{
  const char* tmpString = DivoString.c_str ();

  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::initDivo: %s on
%d", tmpString, _gfxType);
  _divoSource = fpDivoParam::ANY_SOURCE;

  return 1;
}

#ifndef DONT_USE_GUILE
// ----
// scheme interface

SCM fpDivoService::initDivoCB (fpTyped* obj, SCM paramList)
{
  SCM_ASSERT (scm_list_p (paramList) && scm_ilength (paramList) == 1,
       paramList, SCM_WNA, "fpDivoService::initDivoCB");

  fpString tmpString;
  fp_gscm_unbundle (tmpString, gscm_car (paramList));

  fpDivoService* self = (fpDivoService*) obj;
  self->initDivo (tmpString);

  return GSCM_UNSPECIFIED;
}
#else
Elk_Object fpDivoService::initDivoCB (fpTyped* obj, Elk_Object arg_list)

{
  int num_args = Fast_Length(arg_list);
  if (num_args != 1)
    Primitive_Error("fpDivoService::initDivoCB(): wrong number of
arguments.");

  fpString tmpString;
  fp_scheme_unbundle (tmpString, P_Car(arg_list));

  fpDivoService* self = (fpDivoService*) obj;

  self->initDivo (tmpString);

  return Elk_True;
}
#endif

// ----
// create texture and set parameter list
// for all divo boards
// by calling makeVideoTexture

pfTexture* fpDivoService::open (int divoNum)
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::open");

  if ((_divoList[divoNum]._vlTexPath < 0) && _divoList[divoNum]._vTex) {

    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::open: divo
allready opened");
    return _divoList[divoNum]._vTex;
  }

  // open divo board divoNum
  int divoFlag = 1;

  char* tmp;

  tmp = (char *) glGetString(GL_RENDERER);

  if (!strncmp(tmp,"IRL",3)) _gfxType=fpDivoParam::GFX_OX_IR_DIVO;
  else _gfxType=fpDivoParam::GFX_O2_VIDEO;

  // open path for DIVO divoNum
  if (!_divoList[divoNum].open (divoNum, _vTexType, _divoSource,
_gfxType)) {
    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::open: couldn't
open DIVO path");

    divoFlag = 0;
    return 0;
  }

  // start transfer and create texture
  // only if divoboard is present
  if (divoFlag) {
    makeVideoTexture (divoNum);
    return _divoList[divoNum]._vTex;
  }
  return 0;
}

// ----
// enable texture downloading

int fpDivoService::start (int divoNum)
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::start divoNum %d",
divoNum);
  // start is called after opening in drawprocess

  _divoState = fpDivoParam::PLAYING;

  _divoList[divoNum].start();

  return 1;
}

// ----
// disable texture downloading

int fpDivoService::stop (int divoNum)
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::stop divoNum %d",
divoNum);
  _divoState = fpDivoParam::STOPED;

  _divoList[divoNum].stop();
  return 1;
}

// ----
// deallocate all resources

int fpDivoService::free (int divoNum)
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::free divoNum %d",
divoNum);

  // pfDelete (_divoList[divoNum]._vTex);
  // _divoList[divoNum]._vTex = NULL;

  _divoState = fpDivoParam::FREE;
  _divoList[divoNum].free();

  return 1;
}

int fpDivoService::makeVideoTexture (int divoNum)
{
  int numComponents;

  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::makeVideoTexture");

  if (_divoList[divoNum]._vTex != NULL)
    return 0;

  // create texture
  _divoList[divoNum]._vTex = new (pfGetSharedArena ()) pfTexture;

  // set parameters

  _divoList[divoNum]._vTex->setName ("Video Texture");

  int tvxsize, tvysize;
  tvxsize = 1;
  tvysize = 1;
  while (tvxsize < _divoList[divoNum]._divFW) tvxsize <<= 1;
  while (tvysize < _divoList[divoNum]._divFH * 1.0) tvysize <<= 1;

  _divoList[divoNum]._vTex->setFilter (PFTEX_MINFILTER, PFTEX_LINEAR);
  _divoList[divoNum]._vTex->setFilter (PFTEX_MAGFILTER, PFTEX_LINEAR);

  _divoList[divoNum]._vTex->setFormat(PFTEX_SUBLOAD_FORMAT, PF_ON);

  _divoList[divoNum]._vTex->setLoadOrigin (PFTEX_ORIGIN_DEST, 0, 0);

  // tune for IR ??
  switch (_vTexType) {
  case fpDivoParam::VTEX_RGB:
    _divoList[divoNum]._vTex->setFormat (PFTEX_INTERNAL_FORMAT,
PFTEX_RGB_8);
    numComponents = 3;
    break;
  case fpDivoParam::VTEX_RGBA:
    _divoList[divoNum]._vTex->setFormat
(PFTEX_INTERNAL_FORMAT,GL_RGBA8_EXT);
    numComponents = 4;
    break;
  default:
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::makeVideoTexture -
bad texture type");
    pfDelete (_divoList[divoNum]._vTex);
    _divoList[divoNum]._vTex = NULL;
    return 0;
  }

  // capture fields, but not interlaced
  //set size of texture
  _divoList[divoNum]._vTex->setImage((uint *) NULL, 4, tvxsize, tvysize,
1);
  _divoList[divoNum]._vTex->setLoadSize(_divoList[divoNum]._divFW,
_divoList[divoNum]._divFH);

  _divoList[divoNum]._vTex->setFilter(PFTEX_EXTERNAL_FORMAT,
PFTEX_PACK_8);

_divoList[divoNum]._vTex->setLoadMode(PFTEX_LOAD_BASE,PFTEX_BASE_AUTO_SUBLOAD);

//
_divoList[divoNum]._vTex->setLoadMode(PFTEX_LOAD_BASE,PFTEX_BASE_APPLY);

  _divoList[divoNum]._vTex->setLoadMode (PFTEX_LOAD_SOURCE,
PFTEX_SOURCE_VIDEO);
// _divoList[divoNum]._vTex->setLoadMode (PFTEX_LOAD_SOURCE,
PFTEX_SOURCE_IMAGE);
  _divoList[divoNum]._vTex->setLoadMode (PFTEX_LOAD_SOURCE,
PFTEX_SOURCE_DMBUF);

  return 1;
}

//
// ========================= Drawprocess only
===============================

// -- taken from the Sirius service but not really needed here, it can
be deleted!!

void fpDivoService::load (pfPipeWindow* pWin, int divoNum)
{

  // don't do anything without pipe
  if (pWin == 0) {
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::load: no pipe
given");
    return;
  }

  // look for currend state and stop or free divo if neccessary
  if (_divoState == fpDivoParam::NO_DIVO) {
    return;
  }

  VLEvent ev;

  // will be printed out repeatedly
  if (vlCheckEvent(_divoList[divoNum]._vlSrv,
VLSequenceLostMask|VLStreamPreemptedMask|
VLTransferCompleteMask|VLTransferFailedMask |
     VLStreamStartedMask | VLStreamStoppedMask,
     &ev) == -1) {
    //pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::load: event
%d",ev.reason);
    return;
  }
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::load: event
%d",ev.reason);
  switch(ev.reason) {
  case VLSequenceLost:
    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"VLSequenceLost....\n");
    break;
  case VLTransferComplete:
    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"VLTransferComplete....\n");
    if(vlDMBufferGetValid(_divoList[divoNum]._vlSrv,
_divoList[divoNum]._vlTexPath, _divoList[divoNum]._drn, &_buff) == -1) {

        pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"vlDMBufferGetValid
failed....\n");
    } else {
        pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"vlDMBufferGetValid
succeeded....\n");
        *dataPtr = (uint *) dmBufferMapData(_buff);

  int tvxsize, tvysize;
  tvxsize = 1;
  tvysize = 1;
  while (tvxsize < _divoList[divoNum]._divFW) tvxsize <<= 1;
  while (tvysize < _divoList[divoNum]._divFH * 1.0) tvysize <<= 1;
        pfEnable(PFEN_TEXTURE);
    pfTexture *tex = pfGetCurTex();
// _divoList[divoNum]._vTex->setImage((uint *) *dataPtr, 4,
tvxsize, tvysize, 1);
 _divoList[divoNum]._vTex->apply();
        _divoList[divoNum]._vTex->load();

        dmBufferFree(_buff);
    }

// pfEnable(PFEN_TEXTURE);
// _divoList[divoNum]._vTex->apply();
// _divoList[divoNum]._vTex->load();
    break;
  case VLTransferFailed:
    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"VLTransfer FAILED ....\n");
    break;
  case VLStreamStarted:
    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"VLStreamStarted....\n");
    break;
  case VLStreamPreempted:
    cerr << "VLStreamPreempted!\n";
    break;
  case VLStreamBusy:
    cerr << "VLStreamBusy!\n";
    break;
  case VLStreamAvailable:
    cerr << "VLStreamAvailable!\n";
    break;
  default:
    break;
  }

  // don't go further without texture
  if (_divoList[divoNum]._vTex == 0) {
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoService::load: no
texture");
    return;
  }

}

//
// ========================= fpDivoParam ===============================

// ----
// open a path from the divoboard of the given pipe to texture memory

int fpDivoParam::open (int divoNum, VideoTexType textureType, DivoSource
divoSource, GFXType gfxType)
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::open: divo %d,
texType %d, source %d", divoNum, textureType, divoSource);

  // if there is allready a path open, delete it
  if (_currentState != FREE || _vlSrv) {
    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::open: DIVO path
allready open");
    free ();
  }

  // ----
  // depending on the given source, some parameters have to be set

  _currentState = STOPED;
  _currentSource = divoSource;

  // ----
  // setup video texture path

  _deviceNo = divoNum;

  _vlSrv = vlOpenVideo ("");
  if (_vlSrv == NULL) {
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoParam::open: cannot connect
to video server");
    free ();
    return 0;
  }

  _src = vlGetNode (_vlSrv, VL_SRC, VL_VIDEO, VL_ANY);
  if (_src < 0) {
    vlPerror ("vlGetNode Divo (video in)");
    free ();
    return 0;
  }

  _drn = vlGetNode (_vlSrv, VL_DRN, VL_MEM, VL_ANY);
  if (_drn < 0) {
    vlPerror ("vlGetNode Divo (memory)");
    free ();
    return 0;
  }

  _vlTexPath = vlCreatePath (_vlSrv, _deviceNo, _src, _drn);
  if (_vlTexPath < 0) {
    vlPerror ("vlCreatePath Divo (video texture)");
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"vlCreatePath Divo (video texture)
%d",_deviceNo);
    free ();
    return 0;
  }

  if (vlSetupPaths (_vlSrv, (VLPathList)&_vlTexPath, 1, VL_SHARE,
VL_SHARE) < 0) {
    vlPerror ("vlSetupPaths Divo (video texture)");
    free ();
    return 0;
  }

  // ----
  // Settings

  int mask;

  mask = VLStreamStartedMask | VLTransferCompleteMask |
VLTransferFailedMask | VLStreamStoppedMask | VLSequenceLostMask;
  vlSelectEvents( _vlSrv, _vlTexPath, mask);

  // packing
  VLControlValue tex;
  switch (textureType) {
  case VTEX_RGB:
    if (gfxType == fpDivoParam::GFX_OX_IR_DIVO) tex.intVal =
VL_PACKING_0444_8;
    else tex.intVal = VL_PACKING_RGB_8;
    break;
  case VTEX_RGBA:
    if (gfxType == GFX_OX_IR_DIVO) tex.intVal = VL_PACKING_4444_8;
    else tex.intVal = VL_PACKING_ABGR_8;
    break;
  default:
    pfNotify(PFNFY_WARN, PFNFY_PRINT, "fpDivoParam::open: - bad texture
type");
    free ();
    return 0;
  }

  if (vlSetControl (_vlSrv, _vlTexPath, _drn, VL_PACKING, &tex) < 0) {
    vlPerror ("vlSetControl Divo: texture, packing");
    free ();
    return 0;
  }

  // colourspace
  if (gfxType == fpDivoParam::GFX_OX_IR_DIVO) {
    tex.intVal = VL_COLORSPACE_RGB;
    if (vlSetControl (_vlSrv, _vlTexPath, _drn, VL_COLORSPACE, &tex) <0)
{
      vlPerror ("vlSetControl Divo: texture, colorspace");
      free();
      return 0;
    }
  }

  // capturing
  VLControlValue capture;
  capture.intVal = VL_CAPTURE_FIELDS;
  if (vlSetControl (_vlSrv, _vlTexPath, _drn, VL_CAP_TYPE, &capture) <
0) {
    vlPerror ("vlSetControl Divo: texture, capture");
    free ();
    return 0;
  }

  // get size of video-frame

  VLControlValue size;
  if (vlGetControl (_vlSrv, _vlTexPath, _src, VL_SIZE, &size) < 0) {
    vlPerror ("vlGetControl Divo: video in, size");
    free ();
    return 0;
  }
  _divW = size.xyVal.x;
  _divH = size.xyVal.y;

  // get video-field size for texture which is based on field size
  if (vlGetControl(_vlSrv, _vlTexPath, _drn, VL_SIZE, &size) < 0) {
    vlPerror("vlGetControl: video field size for texture");
    free();
    return 0;
  }
  _divFW = size.xyVal.x;
  _divFH = size.xyVal.y;

  // int frameSize;
  // frameSize=vlGetTransferSize(_vlSrv, _vlTexPath);
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::open width %d; height
%d field width %d field height %d", _divW, _divH, _divFW, _divFH);

  DMparams* plist;

  if (dmParamsCreate(&plist)) {
    vlPerror("Video::Start - dmParamsCreate failed!");
    return 0;
  }
  else
    printf("Divo *** dmParamsCreate successfull for O2 and ONYX2 ?!?
(WV)!\n");

  int videoBufCt;

  // dmBufferSetPoolDefaults(plist, 4, frameSize, DM_FALSE,
DM_FALSE);
  dmBufferSetPoolDefaults(plist, 0, 0, DM_FALSE, DM_FALSE);
  dmParamsSetInt(plist, DM_BUFFER_COUNT, 0);
  vlDMGetParams(_vlSrv, _vlTexPath, _drn, plist);
  videoBufCt = dmParamsGetInt(plist, DM_BUFFER_COUNT);
  dmParamsSetInt(plist, DM_BUFFER_COUNT, videoBufCt + 1);
  if (dmBufferCreatePool(plist, &_pool) != DM_SUCCESS) {
    vlPerror("Video::Start Divo - dmBufferCreatePool failed '%s'\n");
  }
  dmParamsDestroy(plist);

  if (!_pool) {
    vlPerror("Divo no pool??");
    return 0;
  }

  // Associate the pool with the path
  if (vlDMPoolRegister(_vlSrv, _vlTexPath, _drn,_pool)) {
    vlPerror("Divo no pool-path association");
    dmBufferDestroyPool(_pool);
    return 0;
  }

  VLControlValue timing, dominance;

  //
  // in 525 ("NTSC"), the odd field is drawn first (higher spacially).
  // in 625 ("PAL"), the even field is drawn first

  if (vlGetControl(_vlSrv, _vlTexPath, _src, VL_TIMING, &timing) <0) {
    vlPerror("VlGetControl of timing");
    return 0;
  }
  F1_is_first = (timing.intVal == VL_TIMING_625_CCIR601);

  // check the FIELD_DOMINANCE only on nessie
  // not on an O2

  char* tmp;

  tmp = (char *) glGetString(GL_RENDERER);

  if (!strncmp(tmp,"IRL",3)) {
    if (vlGetControl(_vlSrv, _vlTexPath, _src, VL_FIELD_DOMINANCE,
&dominance) <0) {
      vlPerror("VlGetControl of dominance");
      return 0;
    }
  }

  F1_is_first ^= (dominance.intVal == VL_F2_IS_DOMINANT);
  return 1;
}

// ----
// start playing

void fpDivoParam::start ()
{
  // VLTransferDescriptor xferDesc;
  int rc;

  if (_currentState != STOPED)
    return;

  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::start");

  // if DIVO has not been opened yet or
  // if it has been stopped and started again
  // texture is already created but the path
  // needs to be reopened
  if (!_vlSrv) {

    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::start opening
DIVO");

    char* tmp;
    fpDivoParam::GFXType _gfxType;

    tmp = (char *) glGetString(GL_RENDERER);
    if (!strncmp(tmp,"IRL",3)) _gfxType=fpDivoParam::GFX_OX_IR_DIVO;
    else _gfxType=fpDivoParam::GFX_O2_VIDEO;

    // open path for DIVO divoNum
    if (!open (_deviceNo, VTEX_RGBA, ANY_SOURCE, _gfxType)) {
      pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoService::start: couldn't
open DIVO path");

      // divoFlag = 0;

      return;
    }
  }

  // link texture with the new or existing path
// _vTex->setLoadVal(PFTEX_LOAD_VIDEO_VLSERVER,(void *) _vlSrv);
// _vTex->setLoadVal(PFTEX_LOAD_VIDEO_VLPATH, (void *) _vlTexPath);
// _vTex->setLoadVal(PFTEX_LOAD_VIDEO_VLDRAIN, (void *) _drn);
// _vTex->setLoadVal(PFTEX_LOAD_DMBUF, (void *) _pool);

  // begin transfer in both cases
  _currentState = PLAYING;

  rc = vlBeginTransfer(_vlSrv, _vlTexPath, 0, NULL);
  if(rc < 0) {
    vlPerror("Divo vlBeginTransfer");
    return;
  }
}

// ----
// stop playing

void fpDivoParam::stop ()
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::stop");
  if (_currentState != PLAYING)
    return;

  _currentState = STOPED;
  vlEndTransfer (_vlSrv, _vlTexPath);
  if (_pool) {
    vlDMPoolDeregister(_vlSrv, _vlTexPath, _drn,_pool);
    dmBufferDestroyPool(_pool);
  }
  vlDestroyPath(_vlSrv, _vlTexPath);

  // free all resources except texture
  if (_vlSrv)
      vlCloseVideo (_vlSrv);

  _vlSrv = 0;
  _vlTexPath = 0;

  _frame = 0;
  _pool =0;
  _currentSource = NO_SOURCE;
}

// ----
// free all resources

void fpDivoParam::free ()
{
  pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "fpDivoParam::free divoNum %d",
_deviceNo);

  if (_currentState == FREE)
    return;

  if (_vlSrv && _vlTexPath) {
    vlEndTransfer (_vlSrv, _vlTexPath);
    vlDestroyPath (_vlSrv, _vlTexPath);
  }

  if (_vlSrv)
    vlCloseVideo (_vlSrv);

  _vlSrv = 0;
  _vlTexPath = 0;

  _frame = 0;
  _pool =0;
  _currentState = FREE;
  _currentSource = NO_SOURCE;
}

#endif


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Wed Nov 18 1998 - 09:33:38 PST

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.