Configuring SDI input/output for passthru input card->gpu->output card

318 views Asked by At

I'm using the Quadro SDI SDK along with my Quadro K6000+ SDI Input & output cards and have converted the included cudaDVP SDK sample to send raw image buffers directly to the GPU from the SDI input card.

In the next step I display the data via opengl bindings. Finally I want to output the same identical data to my output card, and this is where I'm having troubles.

I am getting correct input data and I do manage to output to the screen but there appears to be some data modifications happening in the SDI output pipeline as the outgoing image is not quite correct (wrong colors etc). I'm passing the raw input buffer as can be seen below.

Which output card configuration should I use to match my input settings (see below)?

Which if any modifications to the OpenGL output texture configuration are required (see below)?

Input/output Capture/receive options & GL bindings in order of being called in the application:

........
 Display *dpy = XOpenDisplay(NULL);
 //scan the systems for GPUs
int num_gpus = ScanHW(dpy,gpuList);

if(num_gpus < 1)
    exit(1);

//grab the first GPU for now for DVP
HGPUNV *g = &gpuList[0];

////////////////////////////////////////////////////////////////////////////////////////////////
/// Input related SDI settings and OpenGL settings

// Query input , in our case Video format: NV_CTRL_GVIO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL
XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GVI, 0, 0, NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT, &m_videoFormat); 

//
 // Set desired parameters
//
// Signal format.
XNVCTRLSetTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GVI, 0, 0, NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT, m_videoFormat);
//Bits per component - 10 bits
XNVCTRLSetTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GVI, 0, 0, NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT, NV_CTRL_GVI_BITS_PER_COMPONENT_10);
// Component sampling -422
XNVCTRLSetTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GVI, 0, 0,   NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING, NV_CTRL_GVI_COMPONENT_SAMPLING_422);
// Chroma expansion OFF
XNVCTRLSetTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GVI, 0, 0, NV_CTRL_GVI_REQUESTED_STREAM_CHROMA_EXPAND,   NV_CTRL_GVI_CHROMA_EXPAND_FALSE);

// Query the width and height of the input signal format
XNVCTRLQueryAttribute(dpy, g->deviceXScreen, value, NV_CTRL_GVIO_VIDEO_FORMAT_WIDTH, &m_videoWidth);
XNVCTRLQueryAttribute(dpy, g->deviceXScreen, value, NV_CTRL_GVIO_VIDEO_FORMAT_HEIGHT, &m_videoHeight);


    ....
GLuint m_videoSlot; // Video slot number
GLuint m_vidBuf;  // Video capture buffers
GLint m_bufPitch; // Buffer pitch
GLuint m_vidTex;  // Video capture textures

m_videoSlot = 1;
//////////////////////////////////////
////////// OpenGL related settings
// No video color conversion desired ( we want the raw data, NULL )
glVideoCaptureStreamParameterfvNV(m_videoSlot, 0, GL_VIDEO_COLOR_CONVERSION_MATRIX_NV, NULL);
glVideoCaptureStreamParameterfvNV(m_videoSlot, 0,GL_VIDEO_COLOR_CONVERSION_MAX_NV, NULL);
glVideoCaptureStreamParameterfvNV(m_videoSlot, 0,GL_VIDEO_COLOR_CONVERSION_MIN_NV, NULL);
glVideoCaptureStreamParameterfvNV(m_videoSlot, 0,GL_VIDEO_COLOR_CONVERSION_OFFSET_NV, NULL);

// Set the buffer object capture data format. - IE number of components in a pixel
glVideoCaptureStreamParameterivNV(m_videoSlot, 0, GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV, &GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV);
// Get the video buffer pitch
glGetVideoCaptureStreamivNV(m_videoSlot, 0,  GL_VIDEO_BUFFER_PITCH_NV, &m_bufPitch);
// Bind the buffer
glBindBufferARB(GL_VIDEO_BUFFER_NV, m_vidBuf);
// Allocate required space in video capture buffer
glBufferDataARB(GL_VIDEO_BUFFER_NV, m_bufPitch * m_videoHeight, NULL, GL_STREAM_READ_ARB);
// Bind the buffer to the video capture device.
glBindVideoCaptureStreamBufferNV(m_videoSlot, 0, GL_FRAME_NV, 0);


////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////
/// SDI Output card settings
GLuint m_CudaOutTexture;                // Texture to send to the output device
GLuint m_CudaOutBuffer;                 // Texture to send to the output device
GLuint m_OutTexture;

// Set video format - same as input - NV_CTRL_GVIO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL
XNVCTRLSetAttribute(dpy, m_outputOptions.xscreen, 0, NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT, m_videoFormat);

// Set data format format.
// Attempted several different settings here....
data_format = NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB422;                                                         
//data_format = NV_CTRL_GVO_DATA_FORMAT_X10X10X10_422_PASSTHRU;      
//data_format = NV_CTRL_GVO_DATA_FORMAT_X8X8X8_422_PASSTHRU;                                                          
//data_format = NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB422;                                                    
//data_format = NV_CTRL_GVO_DATA_FORMAT_X12X12X12_422_PASSTHRU;                                                   
//data_format = NV_CTRL_GVO_DATA_FORMAT_Y10CR10CB10_TO_YCRCB444;                                                  
//data_format = NV_CTRL_GVO_DATA_FORMAT_X10X8X8_422_PASSTHRU;                                                     
//data_format = NV_CTRL_GVO_ENABLE_RGB_DATA_DISABLE                                                               
XNVCTRLSetAttribute(dpy, m_outputOptions.xscreen, 0, NV_CTRL_GVO_DATA_FORMAT,  data_format);
// Set sync mode
XNVCTRLSetAttribute(dpy, m_outputOptions.xscreen, 0, NV_CTRL_GVO_SYNC_MODE, NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING);

// Set sync source
XNVCTRLSetAttribute(dpy, m_outputOptions.xscreen, 0, NV_CTRL_GVO_SYNC_SOURCE, NV_CTRL_GVO_SYNC_SOURCE_SDI);
// Set flip queue length
XNVCTRLSetAttribute(dpy, m_outputOptions.xscreen, 0, NV_CTRL_GVO_FLIP_QUEUE_SIZE, 5);

    .....

///////////////////////////////////////////////////////////////////
// OpenGL related settings for output
//Setup the output after the capture is configured.
glGenTextures(1, &m_OutTexture);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, m_OutTexture);
glTexParameterf(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA8, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );

////////////////////////////////////////////////////////
//Setup GL output from cuda
// Create and initialize a texture objects.
glGenBuffersARB(1, &m_CudaOutBuffer);
assert(glGetError() == GL_NO_ERROR);
glBindBufferARB(GL_VIDEO_BUFFER_NV, m_CudaOutBuffer);
assert(glGetError() == GL_NO_ERROR);
// Allocate required space in video capture buffer
glBufferDataARB(GL_VIDEO_BUFFER_NV, pitch * height, NULL, GL_STREAM_COPY);
glGenTextures(1, &m_CudaOutTexture);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, m_CudaOutTexture);
glTexParameterf(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
assert(glGetError() == GL_NO_ERROR);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA8, width,height,
glBindTexture(GL_TEXTURE_RECTANGLE_NV, 0);
//register the buffer objects
cudaRegisterBuffers();
....


  ////////////////////////////////////////////////////////////////
  /////////// Data transfer from GPU to output device buffer (to be outputted to the SDI output card)

GLint inBuf = m_vidBuf;
// Map buffer(s) into CUDA
cudaError_t cerr;
unsigned char *inDevicePtr;
cerr = cudaGLMapBufferObject((void**)&inDevicePtr, inBuf);
cudaCheckErrors("map");
unsigned char *outDevicePtr;
cerr = cudaGLMapBufferObject((void**)&outDevicePtr, m_CudaOutBuffer);
cudaCheckErrors("map");

//
// Dummy CUDA operation:
// Perform CUDA Operations here such as  a kernel call with outDevicePtr and inDevicePtr.
//
unsigned int pitch = m_SDIin.getBufferObjectPitch(0);
unsigned int height = m_SDIin.getHeight();
cudaMemcpy(outDevicePtr,inDevicePtr,pitch*height,cudaMemcpyDeviceToDevice);





  ////////////////////////////////////////////////////////
  /////// output 

GLboolean C_cudaDVP::OutputVideo()
{
    if(!m_SDIoutEnabled)
        return GL_FALSE;
    //send the texture to SDI out.
    glBindTexture(GL_TEXTURE_RECTANGLE_NV, m_OutTexture);
    glEnable(GL_TEXTURE_RECTANGLE_NV);


    glPresentFrameKeyedNV(1, 0,
                0, 0,
                GL_FRAME_NV,
                GL_TEXTURE_RECTANGLE_NV, m_OutTexture, 0,
                GL_NONE, 0, 0);



     GLenum l_eVal = glGetError();
    glBindTexture(GL_TEXTURE_RECTANGLE_NV, 0);

    if (l_eVal != GL_NO_ERROR) {
        fprintf(stderr, "glPresentFameKeyedNV returned error: %s\n", gluErrorString(l_eVal));
        return FALSE;
    }

    return GL_TRUE;
}

.....

// After which we call:

// To skip a costly data copy from video buffer to texture we
// can just bind a video buffer to GL_PIXEL_UNPACK_BUFFER_ARB and call
// glTexSubImage2D referencing into the buffer with the PixelData pointer
// set to 0.
glBindTexture(GL_TEXTURE_RECTANGLE_NV, m_CudaOutTexture);
//glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_SDIin.getBufferObjectHandle(0));
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_CudaOutBuffer);
glPixelStorei(GL_UNPACK_ROW_LENGTH,pitch/4);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, 0);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

//////////////////////////////////////////////////////
0

There are 0 answers