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.
To jest pożądany rezultat:
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ś?
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
Ale prawdopodobnie powinienem być w stanie uzyskać dane z tekstury w spłaszczonej pamięci liniowej? –
To byłoby prawdopodobne rozwiązanie. "cudaMemcpy3D" może być na to przydatny, w przeciwnym razie działa również proste jądro. – talonmies