我将 Quadro SDI SDK 与我的 Quadro K6000+ SDI 输入和输出卡一起使用,并已将包含的 cudaDVP SDK 示例转换为将原始图像缓冲区从 SDI 输入卡直接发送到 GPU。
在下一步中,我通过 opengl 绑定显示数据。最后我想将相同的数据输出到我的输出卡,这就是我遇到麻烦的地方。
我得到了正确的输入数据,并且我确实设法输出到屏幕,但由于输出图像不太正确(颜色错误等),SDI 输出管道中似乎发生了一些数据修改。我正在传递原始输入缓冲区,如下所示。
我应该使用哪种输出卡配置来匹配我的输入设置(见下文)?
如果需要对 OpenGL 输出纹理配置进行任何修改(见下文)?
输入/输出捕获/接收选项和 GL 绑定,按在应用程序中调用的顺序:
........
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);
//////////////////////////////////////////////////////