VideoDecoder.cpp 10.3 KB
/*
 * Copyright 1993-2015 NVIDIA Corporation.  All rights reserved.
 *
 * Please refer to the NVIDIA end user license agreement (EULA) associated
 * with this source code for terms and conditions that govern your use of
 * this software. Any use, reproduction, disclosure, or distribution of
 * this software and related documentation outside the terms of the EULA
 * is strictly prohibited.
 *
 */

#include "VideoDecoder.h"

#include "FrameQueue.h"
#include <cstring>
#include <cassert>
#include <string>

extern "C"
{
#include "libavutil/error.h"
}


bool VideoDecoder::InitDecoder(const CUVIDEOFORMAT &rVideoFormat)
{
	switch (m_VideoCreateFlags)
	{
	case cudaVideoCreate_Default:
		//printf("Default (VP)\n");
		break;

	case cudaVideoCreate_PreferCUDA:
		//printf("Use CUDA decoder\n");
		break;

	case cudaVideoCreate_PreferDXVA:
		//printf("Use DXVA decoder\n");
		break;

	case cudaVideoCreate_PreferCUVID:
		//printf("Use CUVID decoder\n");
		break;

	default:
		//printf("Unknown value\n");
		break;
	}

	// Validate video format.  These are the currently supported formats via NVCUVID
	if (cudaVideoCodec_MPEG1 == rVideoFormat.codec ||
		cudaVideoCodec_MPEG2 == rVideoFormat.codec ||
		cudaVideoCodec_MPEG4 == rVideoFormat.codec ||
		cudaVideoCodec_VC1 == rVideoFormat.codec ||
		cudaVideoCodec_H264 == rVideoFormat.codec ||
		cudaVideoCodec_JPEG == rVideoFormat.codec ||
		cudaVideoCodec_YUV420 == rVideoFormat.codec ||
		cudaVideoCodec_YV12 == rVideoFormat.codec ||
		cudaVideoCodec_NV12 == rVideoFormat.codec ||
		cudaVideoCodec_YUYV == rVideoFormat.codec ||
		cudaVideoCodec_UYVY == rVideoFormat.codec)
		;
	else
	{
		printf("cant supprt video codec: %d\n", rVideoFormat.codec);
		return false;
	}

	if(cudaVideoChromaFormat_Monochrome == rVideoFormat.chroma_format ||
		cudaVideoChromaFormat_420 == rVideoFormat.chroma_format ||
		cudaVideoChromaFormat_422 == rVideoFormat.chroma_format ||
		cudaVideoChromaFormat_444 == rVideoFormat.chroma_format)
		;
	else
	{
		printf("cant supprt video codec format: %d\n", rVideoFormat.chroma_format);
		return false;
	}

	// Fill the decoder-create-info struct from the given video-format struct.
	memset(&oVideoDecodeCreateInfo_, 0, sizeof(CUVIDDECODECREATEINFO));
	// Create video decoder
	oVideoDecodeCreateInfo_.CodecType = rVideoFormat.codec;
	oVideoDecodeCreateInfo_.ulWidth = rVideoFormat.coded_width;
	oVideoDecodeCreateInfo_.ulHeight = rVideoFormat.coded_height;
	oVideoDecodeCreateInfo_.ulNumDecodeSurfaces = FrameQueue::cnMaximumSize;

	// Limit decode memory to 24MB (16M pixels at 4:2:0 = 24M bytes)
	while (oVideoDecodeCreateInfo_.ulNumDecodeSurfaces * rVideoFormat.coded_width * rVideoFormat.coded_height > 16 * 1024 * 1024)
	{
		oVideoDecodeCreateInfo_.ulNumDecodeSurfaces--;
	}

	oVideoDecodeCreateInfo_.ChromaFormat = rVideoFormat.chroma_format;
	oVideoDecodeCreateInfo_.OutputFormat = cudaVideoSurfaceFormat_NV12;
	oVideoDecodeCreateInfo_.DeinterlaceMode = cudaVideoDeinterlaceMode_Adaptive;

	// No scaling
#if 1
	oVideoDecodeCreateInfo_.ulTargetWidth = rVideoFormat.display_area.right - rVideoFormat.display_area.left;
	oVideoDecodeCreateInfo_.ulTargetHeight = rVideoFormat.display_area.bottom - rVideoFormat.display_area.top;
	oVideoDecodeCreateInfo_.display_area.left = 0;
	oVideoDecodeCreateInfo_.display_area.right = oVideoDecodeCreateInfo_.ulTargetWidth;
	oVideoDecodeCreateInfo_.display_area.top = 0;
	oVideoDecodeCreateInfo_.display_area.bottom = oVideoDecodeCreateInfo_.ulTargetHeight;
#else
	oVideoDecodeCreateInfo_.ulTargetWidth = oVideoDecodeCreateInfo_.ulWidth;
	oVideoDecodeCreateInfo_.ulTargetHeight = oVideoDecodeCreateInfo_.ulHeight;
#endif
	oVideoDecodeCreateInfo_.ulNumOutputSurfaces = MAX_FRAME_COUNT;  // We won't simultaneously map more than 8 surfaces
	oVideoDecodeCreateInfo_.ulCreationFlags = m_VideoCreateFlags;
	oVideoDecodeCreateInfo_.vidLock = m_VidCtxLock;
	// create the decoder
	CUresult oResult = cuvidCreateDecoder(&oDecoder_, &oVideoDecodeCreateInfo_);
	//assert(CUDA_SUCCESS == oResult);
	if (oResult != 0)
	{
		char buf[1024];
		av_strerror(oResult, buf, 1024);
		printf("Couldn't cuvidCreateDecoder  %d(%s)", oResult, buf);
		return false;
	}
	return true;
}

VideoDecoder::VideoDecoder(/*const CUVIDEOFORMAT &rVideoFormat,*/
	CUcontext &rContext,
	cudaVideoCreateFlags eCreateFlags,
	CUvideoctxlock &vidCtxLock)
	: m_VidCtxLock(vidCtxLock)
{
	// get a copy of the CUDA context
	m_Context = rContext;
	m_VideoCreateFlags = eCreateFlags;

	//    switch (eCreateFlags)
	//    {
	//        case cudaVideoCreate_Default:
	//            //printf("Default (VP)\n");
	//            break;
	//
	//        case cudaVideoCreate_PreferCUDA:
	//            //printf("Use CUDA decoder\n");
	//            break;
	//
	//        case cudaVideoCreate_PreferDXVA:
	//            //printf("Use DXVA decoder\n");
	//            break;
	//
	//        case cudaVideoCreate_PreferCUVID:
	//            //printf("Use CUVID decoder\n");
	//            break;
	//
	//        default:
	//            //printf("Unknown value\n");
	//            break;
	//    }
	//
	//    // Validate video format.  These are the currently supported formats via NVCUVID
	//    assert(cudaVideoCodec_MPEG1 == rVideoFormat.codec ||
	//           cudaVideoCodec_MPEG2 == rVideoFormat.codec ||
	//           cudaVideoCodec_MPEG4 == rVideoFormat.codec ||
	//           cudaVideoCodec_VC1   == rVideoFormat.codec ||
	//           cudaVideoCodec_H264  == rVideoFormat.codec ||
	//           cudaVideoCodec_JPEG  == rVideoFormat.codec ||
	//           cudaVideoCodec_YUV420== rVideoFormat.codec ||
	//           cudaVideoCodec_YV12  == rVideoFormat.codec ||
	//           cudaVideoCodec_NV12  == rVideoFormat.codec ||
	//           cudaVideoCodec_YUYV  == rVideoFormat.codec ||
	//           cudaVideoCodec_UYVY  == rVideoFormat.codec);
	//
	//    assert(cudaVideoChromaFormat_Monochrome == rVideoFormat.chroma_format ||
	//           cudaVideoChromaFormat_420        == rVideoFormat.chroma_format ||
	//           cudaVideoChromaFormat_422        == rVideoFormat.chroma_format ||
	//           cudaVideoChromaFormat_444        == rVideoFormat.chroma_format);
	//
	//    // Fill the decoder-create-info struct from the given video-format struct.
	//    memset(&oVideoDecodeCreateInfo_, 0, sizeof(CUVIDDECODECREATEINFO));
	//    // Create video decoder
	//    oVideoDecodeCreateInfo_.CodecType           = rVideoFormat.codec;
	//    oVideoDecodeCreateInfo_.ulWidth             = rVideoFormat.coded_width;
	//    oVideoDecodeCreateInfo_.ulHeight            = rVideoFormat.coded_height;
	//    oVideoDecodeCreateInfo_.ulNumDecodeSurfaces = FrameQueue::cnMaximumSize;
	//
	//    // Limit decode memory to 24MB (16M pixels at 4:2:0 = 24M bytes)
	//    while (oVideoDecodeCreateInfo_.ulNumDecodeSurfaces * rVideoFormat.coded_width * rVideoFormat.coded_height > 16*1024*1024)
	//    {
	//        oVideoDecodeCreateInfo_.ulNumDecodeSurfaces--;
	//    }
	//
	//    oVideoDecodeCreateInfo_.ChromaFormat        = rVideoFormat.chroma_format;
	//    oVideoDecodeCreateInfo_.OutputFormat        = cudaVideoSurfaceFormat_NV12;
	//    oVideoDecodeCreateInfo_.DeinterlaceMode     = cudaVideoDeinterlaceMode_Adaptive;
	//
	//    // No scaling
	//#if 1
	//	oVideoDecodeCreateInfo_.ulTargetWidth = rVideoFormat.display_area.right - rVideoFormat.display_area.left;
	//	oVideoDecodeCreateInfo_.ulTargetHeight = rVideoFormat.display_area.bottom - rVideoFormat.display_area.top;
	//	oVideoDecodeCreateInfo_.display_area.left = 0;
	//	oVideoDecodeCreateInfo_.display_area.right = oVideoDecodeCreateInfo_.ulTargetWidth;
	//	oVideoDecodeCreateInfo_.display_area.top = 0;
	//	oVideoDecodeCreateInfo_.display_area.bottom = oVideoDecodeCreateInfo_.ulTargetHeight;
	//#else
	//	oVideoDecodeCreateInfo_.ulTargetWidth       = oVideoDecodeCreateInfo_.ulWidth;
	//    oVideoDecodeCreateInfo_.ulTargetHeight      = oVideoDecodeCreateInfo_.ulHeight;
	//#endif
	//    oVideoDecodeCreateInfo_.ulNumOutputSurfaces = MAX_FRAME_COUNT;  // We won't simultaneously map more than 8 surfaces
	//    oVideoDecodeCreateInfo_.ulCreationFlags     = m_VideoCreateFlags;
	//    oVideoDecodeCreateInfo_.vidLock             = vidCtxLock;
	//    // create the decoder
	//    CUresult oResult = cuvidCreateDecoder(&oDecoder_, &oVideoDecodeCreateInfo_);
	//    //assert(CUDA_SUCCESS == oResult);
	//	if (oResult != 0)
	//	{
	//		char buf[1024];
	//		av_strerror(oResult, buf, 1024);
	//		printf("Couldn't cuvidCreateDecoder  %d(%s)", oResult, buf);
	//		exit(-1);
	//	}
}

VideoDecoder::~VideoDecoder()
{
	if ( oDecoder_ )
	{
		cuvidDestroyDecoder(oDecoder_);
		oDecoder_ = NULL;
	}

	return;
}

cudaVideoCodec
VideoDecoder::codec()
const
{
    return oVideoDecodeCreateInfo_.CodecType;
}

cudaVideoChromaFormat
VideoDecoder::chromaFormat()
const
{
    return oVideoDecodeCreateInfo_.ChromaFormat;
}

unsigned long
VideoDecoder::maxDecodeSurfaces()
const
{
    return oVideoDecodeCreateInfo_.ulNumDecodeSurfaces;
}

unsigned long
VideoDecoder::frameWidth()
const
{
    return oVideoDecodeCreateInfo_.ulWidth;
}

unsigned long
VideoDecoder::frameHeight()
const
{
    return oVideoDecodeCreateInfo_.ulHeight;
}

unsigned long
VideoDecoder::targetWidth()
const
{
    return oVideoDecodeCreateInfo_.ulTargetWidth;
}

unsigned long
VideoDecoder::targetHeight()
const
{
    return oVideoDecodeCreateInfo_.ulTargetHeight;
}

void
VideoDecoder::decodePicture(CUVIDPICPARAMS *pPictureParameters, CUcontext *pContext)
{
    // Handle CUDA picture decode (this actually calls the hardware VP/CUDA to decode video frames)
    CUresult oResult = cuvidDecodePicture(oDecoder_, pPictureParameters);
    //assert(CUDA_SUCCESS == oResult);
}

int
VideoDecoder::mapFrame(int iPictureIndex, CUdeviceptr *ppDevice, unsigned int *pPitch, CUVIDPROCPARAMS *pVideoProcessingParameters)
{
    CUresult oResult = cuvidMapVideoFrame(oDecoder_,
                                          iPictureIndex,
                                          ppDevice,
                                          pPitch, pVideoProcessingParameters);
	//printf("pPitch: %d\n", *pPitch);
	return oResult;
	/*assert(CUDA_SUCCESS == oResult);
    assert(0 != *ppDevice);
    assert(0 != *pPitch);*/
}

void
VideoDecoder::unmapFrame(CUdeviceptr pDevice)
{
    CUresult oResult = cuvidUnmapVideoFrame(oDecoder_, pDevice);
    assert(CUDA_SUCCESS == oResult);
}