c++ - versiones - sdk nvidia cuda
Entrada del codificador de video NVIDIA CUDA(NVCUVENC) de la matriz de texturas del dispositivo (2)
La aplicación nvEncoder se utiliza para la conversión de códecs, para procesar a través de la GPU su cuda utilizada y para comunicarse con el hardware que utiliza la API de nvEncoder. en esta aplicación, la lógica se lee yuv datos en el buffer de entrada y almacena ese contenido en la memoria y luego comienza a codificar los marcos. y en paralelo escriba el cuadro de codificación en el archivo de salida.
El manejo del búfer de entrada está disponible en la función nvRead y está disponible en nvFileIO.h
Cualquier otra ayuda requerida deja un mensaje aquí ...
Estoy modificando la muestra de codificación del Codificador de Video CUDA (NVCUVENC) que se encuentra en el paquete de muestras del SDK para que los datos no provengan de archivos yuv externos (como se hace en la muestra) sino de cudaArray que se rellena desde la textura.
Así que el método API clave que codifica el marco es:
int NVENCAPI NVEncodeFrame(NVEncoder hNVEncoder, NVVE_EncodeFrameParams *pFrmIn, unsigned long flag, void *pData);
Si lo hago bien el param:
CUdeviceptr dptr_VideoFrame
se supone que debe pasar los datos para codificar. Pero realmente no he entendido cómo conectarlos con algunos datos de textura en la GPU. El código fuente de muestra es muy vago, ya que funciona con la entrada de los archivos de CPU yuv.
Por ejemplo, en main.cpp, líneas 555 -560 hay un bloque siguiente:
// If dptrVideoFrame is NULL, then we assume that frames come from system memory, otherwise it comes from GPU memory
// VideoEncoder.cpp, EncodeFrame() will automatically copy it to GPU Device memory, if GPU device input is specified
if (pCudaEncoder->EncodeFrame(efparams, dptrVideoFrame, cuCtxLock) == false)
{
printf("/nEncodeFrame() failed to encode frame/n");
}
Por lo tanto, a partir del comentario, parece que dptrVideoFrame debe rellenarse con los datos de Yuv que vienen del dispositivo para codificar el marco. Pero no hay un lugar donde se explique cómo hacerlo.
ACTUALIZAR:
Me gustaría compartir algunos hallazgos. Primero, logré codificar los datos de la textura de Frame Buffer. El problema ahora es que el video de salida es un desastre.
Ese es el resultado deseado:
Esto es lo que hago:
En el lado de OpenGL, tengo 2 FBO personalizados; primero se reproduce la escena normalmente. Luego, la textura del primer FBO se usa para representar la pantalla cuádruple en el segundo FBO haciendo la conversión RGB -> YUV en el sombreador de fragmentos.
La textura adjunta al segundo FBO se asigna luego al recurso CUDA. Luego codifico la textura actual así:
void CUDAEncoder::Encode(){
NVVE_EncodeFrameParams efparams;
efparams.Height = sEncoderParams.iOutputSize[1];
efparams.Width = sEncoderParams.iOutputSize[0];
efparams.Pitch = (sEncoderParams.nDeviceMemPitch ? sEncoderParams.nDeviceMemPitch : sEncoderParams.iOutputSize[0]);
efparams.PictureStruc = (NVVE_PicStruct)sEncoderParams.iPictureType;
efparams.SurfFmt = (NVVE_SurfaceFormat)sEncoderParams.iSurfaceFormat;
efparams.progressiveFrame = (sEncoderParams.iSurfaceFormat == 3) ? 1 : 0;
efparams.repeatFirstField = 0;
efparams.topfieldfirst = (sEncoderParams.iSurfaceFormat == 1) ? 1 : 0;
if(_curFrame > _framesTotal){
efparams.bLast=1;
}else{
efparams.bLast=0;
}
//----------- get cuda array from the texture resource -------------//
checkCudaErrorsDrv(cuGraphicsMapResources(1,&_cutexResource,NULL));
checkCudaErrorsDrv(cuGraphicsSubResourceGetMappedArray(&_cutexArray,_cutexResource,0,0));
/////////// copy data into dptrvideo frame //////////
// LUMA based on CUDA SDK sample//////////////
CUDA_MEMCPY2D pcopy;
memset((void *)&pcopy, 0, sizeof(pcopy));
pcopy.srcXInBytes = 0;
pcopy.srcY = 0;
pcopy.srcHost= NULL;
pcopy.srcDevice= 0;
pcopy.srcPitch =efparams.Width;
pcopy.srcArray= _cutexArray;///SOME DEVICE ARRAY!!!!!!!!!!!!! <--------- to figure out how to fill this.
/// destination //////
pcopy.dstXInBytes = 0;
pcopy.dstY = 0;
pcopy.dstHost = 0;
pcopy.dstArray = 0;
pcopy.dstDevice=dptrVideoFrame;
pcopy.dstPitch = sEncoderParams.nDeviceMemPitch;
pcopy.WidthInBytes = sEncoderParams.iInputSize[0];
pcopy.Height = sEncoderParams.iInputSize[1];
pcopy.srcMemoryType=CU_MEMORYTYPE_ARRAY;
pcopy.dstMemoryType=CU_MEMORYTYPE_DEVICE;
// CHROMA based on CUDA SDK sample/////
CUDA_MEMCPY2D pcChroma;
memset((void *)&pcChroma, 0, sizeof(pcChroma));
pcChroma.srcXInBytes = 0;
pcChroma.srcY = 0;// if I uncomment this line I get error from cuda for incorrect value.It does work in CUDA SDK original sample SAMPLE//sEncoderParams.iInputSize[1] << 1; // U/V chroma offset
pcChroma.srcHost = NULL;
pcChroma.srcDevice = 0;
pcChroma.srcArray = _cutexArray;
pcChroma.srcPitch = efparams.Width >> 1; // chroma is subsampled by 2 (but it has U/V are next to each other)
pcChroma.dstXInBytes = 0;
pcChroma.dstY = sEncoderParams.iInputSize[1] << 1; // chroma offset (srcY*srcPitch now points to the chroma planes)
pcChroma.dstHost = 0;
pcChroma.dstDevice = dptrVideoFrame;
pcChroma.dstArray = 0;
pcChroma.dstPitch = sEncoderParams.nDeviceMemPitch >> 1;
pcChroma.WidthInBytes = sEncoderParams.iInputSize[0] >> 1;
pcChroma.Height = sEncoderParams.iInputSize[1]; // U/V are sent together
pcChroma.srcMemoryType = CU_MEMORYTYPE_ARRAY;
pcChroma.dstMemoryType = CU_MEMORYTYPE_DEVICE;
checkCudaErrorsDrv(cuvidCtxLock(cuCtxLock, 0));
checkCudaErrorsDrv( cuMemcpy2D(&pcopy));
checkCudaErrorsDrv( cuMemcpy2D(&pcChroma));
checkCudaErrorsDrv(cuvidCtxUnlock(cuCtxLock, 0));
//=============================================
// If dptrVideoFrame is NULL, then we assume that frames come from system memory, otherwise it comes from GPU memory
// VideoEncoder.cpp, EncodeFrame() will automatically copy it to GPU Device memory, if GPU device input is specified
if (_encoder->EncodeFrame(efparams, dptrVideoFrame, cuCtxLock) == false)
{
printf("/nEncodeFrame() failed to encode frame/n");
}
checkCudaErrorsDrv(cuGraphicsUnmapResources(1, &_cutexResource, NULL));
// computeFPS();
if(_curFrame > _framesTotal){
_encoder->Stop();
exit(0);
}
_curFrame++;
}
Configuré los parámetros del codificador a partir de los archivos .cfg incluidos con la muestra del codificador CUDA SDK. Así que aquí utilizo la configuración 704x480-h264.cfg. Los probé todos y obtengo resultados siempre muy feos.
Sospecho que el problema está en algún lugar de CUDA_MEMCPY2D para la configuración de parámetros de objetos de luma y croma. Puede ser el tono, el ancho y las dimensiones de altura incorrectos. Configuro la ventana gráfica del mismo tamaño que el video (704,480) y comparé los parámetros con los utilizados en la muestra CUDA SDK, pero No tengo ni idea de dónde está el problema. Alguien?
Primero: Me metí con Cuda Video Encoder y tuve muchos problemas. Pero me parece que lo conviertes en valores de Yuv, pero como en una conversión de Píxeles (como AYUV 4: 4: 4). Afaik, necesita el tipo correcto de YUV con relleno y compresión (valores de color para más de un píxel como 4: 2: 0). Una buena visión general de las alineaciones YUV se puede ver aquí:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx
Por lo que recuerdo, tienes que usar la alineación NV12 para Cuda Encoder.