Module: qvinvout.cpp

class QVinVout
.h

constructorQVinVout(QDraw *draw)
destructor~QVinVout()
SetGenlockvoid SetGenlock(bool gl)
SetBuffersvoid SetBuffers(int bufs)
Createbool Create()

Flat functions
 

stopitstatic void stopit(int)
runitstatic void runit(void *runObject)

class QVinVout
.h

Runvoid Run()
Threadvoid Thread()


/*
 * QVinVout - video in -> video out (using QDM classes)
 * 14-09-98: Created!
 * 13-11-99: Support for VL_65; not yet tested!!!
 * BUGS:
 * - dtor should kill thread
 * NOTES:
 * - DM: vin -> vinPool -> vout
 * - Very handy for SCREEN->VIDEO OUT
 * (C) MG/RVG
 */

#include <qlib/common/dmedia.h>
#include <qlib/vinvout.h>
#include <qlib/app.h>
#include <signal.h>
#include <sys/wait.h>
#include <qlib/debug.h>
DEBUG_ENABLE

// Default video timing if not deduced
#define DEFAULT_TIMING	VL_TIMING_625_CCIR601

// Default #buffers to use (they store fields, thus frames=buffers/2)
#define DEFAULT_BUFFERS	10

QVinVout::QVinVout(QDraw *draw)
{ int w,h;
  timing=DEFAULT_TIMING;
  if(draw)
  { // Deduce timing
    w=draw->GetWidth();
    h=draw->GetHeight();
    if(w==720)
    { if(h==486)timing=VL_TIMING_525_CCIR601;
      else timing=VL_TIMING_625_CCIR601;
    } else if(w==768)
    { timing=VL_TIMING_625_SQ_PIX;
    } else if(w==640)
    { timing=VL_TIMING_525_SQ_PIX;
    }
    ox=draw->GetX();
    oy=draw->GetY();
  } else
  { ox=oy=0;
  }
  genlock=TRUE;
  buffers=DEFAULT_BUFFERS;
  vClass=VL_SCREEN;
  vSource=VL_ANY;
  vin=0;
  vout=0;
  vinPool=0;
  readThreadPID=-1;
}
QVinVout::~QVinVout()
{
  // Kill proc
  if(readThreadPID!=-1)
  { kill(readThreadPID,SIGTERM);
    waitpid(readThreadPID,0,0);
  }
  if(vin)delete vin;
  if(vout)delete vout;
  if(vinPool)delete vinPool;
}

/*************
* PRE-CREATE *
*************/
void QVinVout::SetGenlock(bool gl)
{ genlock=gl;
  if(vout)vout->SetGenlock(gl);
}
void QVinVout::SetBuffers(int bufs)
{ buffers=bufs;
}

bool QVinVout::Create()
{
  // Create DM objects
  vin=new QDMVideoIn(VL_ANY,VL_SCREEN);
  vin->SetTiming(timing);
  vin->SetPacking(VL_PACKING_YVYU_422_8);
  vin->SetLayout(VL_LAYOUT_LINEAR);
  vin->SetCaptureType(VL_CAPTURE_NONINTERLEAVED);
  vin->SetOrigin(ox,oy);
  //vin->SetZoomSize(texWid,texHgt);

  vout=new QDMVideoOut();
  vout->SetPacking(VL_PACKING_YVYU_422_8);
  vout->SetLayout(VL_LAYOUT_LINEAR);
  vout->SetCaptureType(VL_CAPTURE_NONINTERLEAVED);
  //vout->SetTiming(VL_TIMING_625_CCIR601);
  vout->SetTiming(timing);
  vout->SetGenlock(genlock);

  // Pools; video input, JPEG-encoded fields/frames
  vinPool=new QDMBPool(buffers,vin->GetTransferSize(),FALSE,FALSE);
  vinPool->AddProducer(vin);
  vinPool->AddConsumer(vout);
  if(!vinPool->Create())
  { qerr("Can't create vinPool");
    return FALSE;
  }
  // Register pool
  vin->RegisterPool(vinPool);
  return TRUE;
}

static void stopit(int)
{
  qwarn("QVinVout: stopit() called to end thread\n");
  exit(0);
}

static void runit(void *runObject)
{ QVinVout *v;
  v=(QVinVout*)runObject;
//qdbg("runit: v=%p\n",v);
  v->Thread();
}

void QVinVout::Run()
{
  vin->Start();
  vout->Start();
  // Spawn thread
//qdbg("QVV:Run this=%p\n",this);
  readThreadPID=sproc(runit,PR_SADDR|PR_SFDS,this);
  if(readThreadPID<0)
  { qerr("QVinVout::Run(); can't spawn thread");
  }
}

void QVinVout::Thread()
{
  // Handle stream events
  fd_set fdr;
  int    maxFD;
  VLEvent vlEvent;
  DMbuffer dmb;

  // Let's die when we catch sigterm from our parent too.
  signal(SIGTERM,stopit);

  // Let's die when our parent dies
  prctl(PR_TERMCHILD,NULL);

  maxFD=vin->GetFD();
  while(1)
  {
    FD_ZERO(&fdr);
    FD_SET(vin->GetFD(),&fdr);
    if(select(maxFD+1,&fdr,0,0,0)==-1)
    { perror("select"); return; }
    if(FD_ISSET(vin->GetFD(),&fdr))
    {
      //qdbg("vin event\n");
      vin->GetEvent(&vlEvent);
      /*qdbg("vin event (%s)\n",
        app->GetVideoServer()->Reason2Str(vlEvent.reason));*/
      if(vlEvent.reason==VLTransferComplete)
      { 
#ifdef USE_VL_65
        vlDMBufferGetValid(app->GetVideoServer()->GetSGIServer(),
          vin->GetPath()->GetSGIPath(),
          vin->GetSourceNode()->GetSGINode(),&dmb);
#else
        vlEventToDMBuffer(&vlEvent,&dmb);
#endif
        // Send to video out
        vout->Send(dmb);
        dmBufferFree(dmb);
      } else if(vlEvent.reason==VLSequenceLost)
      { qdbg("QVinVout: sequenceLost: field=%d, number=%d, count=%d\n",
          vlEvent.vlsequencelost.field,
          vlEvent.vlsequencelost.number,
          vlEvent.vlsequencelost.count);
      } else
      { //qdbg("event reason %d\n",vlEvent.reason);
        qdbg("QVinVout: event %s\n",
          app->GetVideoServer()->Reason2Str(vlEvent.reason));
      }
    } else
    { qerr("QVinVout: unknown stream event\n");
    }
  }
}