NVIDIA CUDA Video Encoder (NVCUVENC) input from device texture array

je suis en modifiant CUDA Video Encoder (NVCUVENC) encodage de l'échantillon trouvé dans le paquet SDK samples de sorte que les données ne proviennent pas de fichiers yuv externes (comme c'est fait dans l'échantillon ) mais de cudaArray qui est rempli à partir de la texture.

donc la méthode API clé qui code le frame est:

int NVENCAPI NVEncodeFrame(NVEncoder hNVEncoder, NVVE_EncodeFrameParams *pFrmIn, unsigned long flag, void *pData); 

Si je comprends bien le param :

CUdeviceptr dptr_VideoFrame

est censé transmettre les données à encoder.Mais je n'ai vraiment pas compris comment le relier avec une certaine texture les données sur les GPU.Le code source de l'échantillon est très vague à ce sujet car il fonctionne avec CPU fichiers yuv entrée.

Par exemple dans la principale.cpp, lignes 555 -560 il y a le bloc suivant:

    // 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 framen");
    }

donc, d'après le commentaire, il semble que dptrVideoFrame doit être rempli avec yuv données provenant de l'appareil pour coder l'image.Mais il n'y a pas de lieu où il est expliqué comment faire.

mise à jour:

je voudrais partager quelques Conclusion.Tout d'abord, j'ai réussi à encoder des données à partir de la texture du tampon.Le problème maintenant est que la vidéo de sortie est un gâchis. enter image description here

Qui est le résultat souhaité:

enter image description here

Voici ce que je fais :

côté OpenGL, j'ai 2 FBOs personnalisés-d'abord, la scène y est rendue normalement .Puis la texture du premier FBO est utilisée pour rendre le quad de l'écran dans le second FBO faisant la conversion RGB - > YUV dans le fragment Shader.

la texture attachée à la seconde FBO est mappée puis à la ressource CUDA. Puis j'encode la texture courante comme ceci:

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 framen");
    }
    checkCudaErrorsDrv(cuGraphicsUnmapResources(1, &_cutexResource, NULL));
    //  computeFPS();

    if(_curFrame > _framesTotal){
        _encoder->Stop();
        exit(0);
    }
    _curFrame++;

}

j'ai paramétré les paramètres de L'encodeur à partir du.fichiers cfg inclus avec L'échantillon D'encodeur SDK de CUDA.Donc ici j'utilise 704x480-h264.cfg de l'installation .J'ai tout essayé et j'ai toujours eu des résultats aussi moches.

je soupçonne que le problème est quelque part dans CUDA_MEMCPY2D pour luma et chroma objets params setup .Peut-être tort, la hauteur , la largeur ,la hauteur dimension.J'ai paramétré le viewport de la même taille que la vidéo (704,480) et j'ai comparé les paramètres à ceux utilisés dans L'échantillon SDK de CUDA, mais je n'ai aucune idée d'où vient le problème. Quiconque ?

18
demandé sur Michael IV 2013-03-05 00:44:04

2 réponses

D'abord: j'ai fait avec CUDA Video Encoder, et j'ai eu beaucoup de problèmes avec. Mais il me semble que c'est comme si vous le convertissiez en valeurs Yuv, mais comme une conversion D'un Pixel sur un (comme AYUV 4:4:4). Afaik vous avez besoin du type correct de YUV avec le rembourrage et la compression (valeurs de couleur pour plus d'un Pixel comme 4:2:0). Un bon aperçu de YUV-alignments peut être vu ici:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs. 85).aspx

autant que je me souvienne, vous devez utiliser l'alignement NV12 pour le codeur Cuda.

2
répondu thewhiteambit 2013-04-17 12:57:39

nvEncoder application est utilisé pour la conversion codec, pour le traitement sur GPU son cuda utilisé et de communiquer avec le matériel il utilise API de nvEncoder. dans cette logique d'application est lu données yuv dans le tampon d'entrée et de stocker ce contenu dans la mémoire, puis commencer à encoder les cadres. et écrire en parallèle le cadre d'encodage dans le fichier de sortie.

manipulation du tampon d'entrée est disponible dans la fonction nvRead et il est disponible dans nvFileIO.h

toute autre aide requise message ici...

1
répondu neer 2015-02-23 09:36:07