2013-03-04 4 views
17

Modyfikuję próbkę kodującą CUDA Video Encoder (NVCUVENC) znajdującą się w pakiecie próbek SDK, aby dane nie pochodziły z zewnętrznych plików yuv (jak to jest w przypadku próbki), ale z cudaArray który jest wypełniony z tekstury.Dane wejściowe NVIDIA CUDA Video Encoder (NVCUVENC) z tablicy wzorów urządzeń

Więc kluczem metoda API, który koduje ramkę jest:

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

Jeśli mam rację param:

CUdeviceptr dptr_VideoFrame 

ma przekazać dane do encode.But Naprawdę Haven zrozumiał, jak połączyć to z niektórymi danymi tekstur na GPU. Przykładowy kod źródłowy jest bardzo niejasny, ponieważ działa z wejściami plików yuv CPU.

Na przykład w main.cpp, linie 555 -560 tam jest następujący blok:

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

Tak, z komentarzem, wydaje się dptrVideoFrame należy wypełnić dane YUV pochodzących z urządzenia do kodowania rama. Ale nie ma miejsca, gdzie wyjaśniono, jak to zrobić.

UPDATE:

Chciałbym podzielić się findings.First, udało mi się zakodować dane z bufora ramki texture.The problemem teraz jest to, że wyjście wideo jest bałagan. enter image description here

To jest pożądany rezultat:

enter image description here

Oto co mam zrobić:

Na stronie OpenGL Mam 2 niestandardowych FBOs pierwszego dostaje scenę świadczonych normalnie do niego .Następnie tekstura z pierwszego FBO służy do renderowania ekranu quada do drugiego FBO wykonującego konwersję RGB -> YUV w module cieniowania fragmentów.

Tekstura dołączona do drugiego pliku FBO jest odwzorowywana na zasób CUDA. Potem kodować bieżącą fakturę tak:

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++; 

} 

ustawić Encoder params z plików .cfg dołączone CUDA SDK Encoder sample.So Używam tutaj 704x480-h264.cfg setup .I próbowała wszystkie z nich i uzyskiwanie zawsze podobnie brzydkich rezultatów.

Podejrzewam, że problem jest gdzieś w CUDA_MEMCPY2D dla ustawień paramatycznych obiektów luma i chroma. Może to być niewłaściwy skok, szerokość, wysokość. Ustawiłem rzutnię o tym samym rozmiarze co wideo (704,480) i porównałem parametry do tych używanych w Próbka SDK CUDA, ale nie ma pojęcia, gdzie jest problem. Ktoś?

+0

nie mam żadnego doświadczenia z kodera wideo , ale patrząc na API wydaje się, że nie będziesz w stanie przekazać tablicy CUDA. Pikowana pamięć liniowa powinna działać, ale tekstura prawdopodobnie nie. – talonmies

+0

Ale prawdopodobnie powinienem być w stanie uzyskać dane z tekstury w spłaszczonej pamięci liniowej? –

+0

To byłoby prawdopodobne rozwiązanie. "cudaMemcpy3D" może być na to przydatny, w przeciwnym razie działa również proste jądro. – talonmies

Odpowiedz

2

Po pierwsze: zgramoliłem się z Encoderem wideo Cuda i miałem wiele problemów. Ale wygląda na to, że przekonwertowałeś ją na wartości Yuv, ale jako jedną na jedną konwersję Pixela (jak AYUV 4: 4: 4). Afaik potrzebujesz właściwego rodzaju YUV z dopełnieniem i kompresją (wartości kolorów dla więcej niż jednego Pixela jak 4: 2: 0).Dobry przegląd YUV trasowania można zobaczyć tutaj:

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

O ile pamiętam, trzeba użyć wyrównanie NV12 CUDA Encoder.

1

Aplikacja nvEncoder służy do konwersji kodeków, do przetwarzania przez GPU wykorzystywanej cuda i komunikowania się ze sprzętem używa API API nvEncoder. w tej aplikacji logika jest czytana dane yuv w buforze wejściowym i przechowywać tę zawartość w pamięci, a następnie rozpocząć kodowanie ramek. i równolegle zapisz ramkę kodowania do pliku wyjściowego.

Postępowanie z bufora wejściowego jest dostępny w funkcji nvRead i jest on dostępny w nvFileIO.h

inna pomoc wymagane zostawić wiadomość tutaj ...