Подтвердить что ты не робот

Входной видеокодер NVIDIA CUDA (NVCUVENC) из массива текстуры устройства

Я модифицирую образец кодировки CUDA Video Encoder (NVCUVENC), найденный в пакете образцов SDK, так что данные поступают не из внешних файлов yuv (как выполняется в образце), но из cudaArray, который заполняется из текстуры.

Таким образом, ключевой API-метод, который кодирует кадр:

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

Если я получу это правильно, param:

CUdeviceptr dptr_VideoFrame

должен передавать данные для кодирования. Но я действительно не понял, как подключить его к некоторым данным текстуры на графическом процессоре. Исходный код образца очень смутно, поскольку он работает с входом файлов CPU yuv.

Например, в main.cpp, строках 555 -560 имеется следующий блок:

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

Итак, из комментария кажется, что dptrVideoFrame должен быть заполнен данными yuv, поступающими с устройства для кодирования кадра. Но нет места, где объясняется, как это сделать.

UPDATE:

Я хотел бы поделиться некоторыми выводами. Во-первых, мне удалось кодировать данные из текстуры буфера кадров. Проблема в том, что выходное видео беспорядок. enter image description here

Это желаемый результат:

enter image description here

Вот что я делаю:

На стороне OpenGL у меня есть 2 пользовательских FBOs - сначала получает сцену, обычно отображаемую в ней. Затем текстура из первого FBO используется для рендеринга экрана в секунду во втором FBO, выполняющем преобразование RGB → YUV в шейдере фрагмента.

Текстура, привязанная ко второму FBO, отображается затем на ресурс CUDA. Затем я кодирую текущую текстуру следующим образом:

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

}

Я установил параметры Encoder из файлов .cfg, включенных в образец CUDA SDK Encoder. Здесь я использую настройку 704x480-h264.cfg. Я пробовал все их и получал всегда аналогичный уродливый результат.

Я подозреваю, что проблема находится где-то в CUDA_MEMCPY2D для настройки параметров яркости и цветности объектов. Возможно, это неправильная высота, ширина, высота. Я устанавливаю видовое окно того же размера, что и видео (704 480), и сравнивает параметры с теми, которые используются в CUDA SDK, но не понял, где проблема. Кто угодно?

4b9b3361

Ответ 1

Во-первых: я возился с Cuda Video Encoder и имел массу проблем. Но это выглядит так, как будто вы конвертируете его в значения Yuv, но как конвертирование с одним пикселем (например, AYUV 4: 4: 4). Afaik вам нужен правильный вид YUV с заполнением и сжатием (значения цвета для более чем одного пикселя, например 4: 2: 0). Хороший обзор выравниваний YUV можно увидеть здесь:

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

Насколько я помню, вам нужно использовать выравнивание NV12 для Cuda Encoder.

Ответ 2

Приложение nvEncoder используется для преобразования кодеков, для обработки на GPU используемого cuda и связи с оборудованием использует API nvEncoder. в этом приложении логика считывает данные во входном буфере и сохраняет это содержимое в памяти, а затем начинает кодирование кадров. и параллельная запись кадра кодирования в выходной файл.

Обработка входного буфера доступна в функции nvRead и доступна в nvFileIO.h

любая другая помощь требуется оставить здесь сообщение...