Install any skill in seconds. Free to start, no credit card required.
Get Started Free →NVIDIA hardware video encoding/decoding integration. Configure NVENC encoding parameters, set up NVDEC decoding pipelines, handle codec configurations, integrate with CUDA for pre/post processing, and manage video memory surfaces.
.claude/skills/a5c-ai-nvenc-nvdec/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 16% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 41% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 93% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 123% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 272% | 0% |
You are nvenc-nvdec - a specialized skill for NVIDIA hardware video encoding and decoding integration. This skill provides expert capabilities for GPU-accelerated video processing.
This skill enables AI-powered video processing including:
Initialize hardware encoder:
c#include <nvEncodeAPI.h> // Create encoder instance NV_ENCODE_API_FUNCTION_LIST nvenc = {NV_ENCODE_API_FUNCTION_LIST_VER}; NvEncodeAPICreateInstance(&nvenc); void* encoder = NULL; NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS sessionParams = { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER}; sessionParams.device = cudaDevice; sessionParams.deviceType = NV_ENC_DEVICE_TYPE_CUDA; sessionParams.apiVersion = NVENCAPI_VERSION; nvenc.nvEncOpenEncodeSessionEx(&sessionParams, &encoder); // Query encoder capabilities NV_ENC_CAPS_PARAM capsParam = {NV_ENC_CAPS_PARAM_VER}; capsParam.capsToQuery = NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES; int capsVal; nvenc.nvEncGetEncodeCaps(encoder, NV_ENC_CODEC_H264_GUID, &capsParam, &capsVal);
Configure encoder parameters:
c// Initialize encoder configuration NV_ENC_INITIALIZE_PARAMS initParams = {NV_ENC_INITIALIZE_PARAMS_VER}; NV_ENC_CONFIG encodeConfig = {NV_ENC_CONFIG_VER}; initParams.encodeConfig = &encodeConfig; // Get preset configuration NV_ENC_PRESET_CONFIG presetConfig = {NV_ENC_PRESET_CONFIG_VER}; presetConfig.presetCfg = {NV_ENC_CONFIG_VER}; nvenc.nvEncGetEncodePresetConfigEx(encoder, NV_ENC_CODEC_H264_GUID, NV_ENC_PRESET_P4_GUID, // Balanced preset NV_ENC_TUNING_INFO_HIGH_QUALITY, &presetConfig); memcpy(&encodeConfig, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); // Set basic parameters initParams.encodeGUID = NV_ENC_CODEC_H264_GUID; initParams.presetGUID = NV_ENC_PRESET_P4_GUID; initParams.encodeWidth = 1920; initParams.encodeHeight = 1080; initParams.frameRateNum = 60; initParams.frameRateDen = 1; initParams.enablePTD = 1; // Enable picture type decision // Rate control encodeConfig.rcParams.rateControlMode = NV_ENC_PARAMS_RC_VBR; encodeConfig.rcParams.averageBitRate = 8000000; // 8 Mbps encodeConfig.rcParams.maxBitRate = 12000000; // 12 Mbps max // B-frames and lookahead encodeConfig.frameIntervalP = 3; // I/P frame interval encodeConfig.rcParams.lookaheadDepth = 20; encodeConfig.rcParams.enableLookahead = 1; // Initialize encoder nvenc.nvEncInitializeEncoder(encoder, &initParams);
Setup HEVC encoding:
c// HEVC-specific configuration initParams.encodeGUID = NV_ENC_CODEC_HEVC_GUID; NV_ENC_CONFIG_HEVC* hevcConfig = &encodeConfig.encodeCodecConfig.hevcConfig; hevcConfig->chromaFormatIDC = 1; // 4:2:0 hevcConfig->pixelBitDepthMinus8 = 0; // 8-bit hevcConfig->idrPeriod = encodeConfig.gopLength; hevcConfig->enableIntraRefresh = 0; hevcConfig->maxCUSize = NV_ENC_HEVC_CUSIZE_32x32; hevcConfig->minCUSize = NV_ENC_HEVC_CUSIZE_8x8; // 10-bit HDR hevcConfig->pixelBitDepthMinus8 = 2; // 10-bit hevcConfig->chromaFormatIDC = 1; // Tier and level hevcConfig->tier = NV_ENC_TIER_HEVC_MAIN; hevcConfig->level = NV_ENC_LEVEL_HEVC_51;
Initialize hardware decoder:
c#include <nvcuvid.h> // Create CUDA video parser CUVIDPARSERPARAMS parserParams = {}; parserParams.CodecType = cudaVideoCodec_H264; parserParams.ulMaxNumDecodeSurfaces = 4; parserParams.ulMaxDisplayDelay = 2; parserParams.pUserData = this; parserParams.pfnSequenceCallback = HandleVideoSequence; parserParams.pfnDecodePicture = HandlePictureDecode; parserParams.pfnDisplayPicture = HandlePictureDisplay; CUvideoparser parser; cuvidCreateVideoParser(&parser, &parserParams); // Sequence callback - create decoder int HandleVideoSequence(void* userData, CUVIDEOFORMAT* format) { CUVIDDECODECREATEINFO createInfo = {}; createInfo.CodecType = format->codec; createInfo.ulWidth = format->coded_width; createInfo.ulHeight = format->coded_height; createInfo.ulNumDecodeSurfaces = 8; createInfo.ChromaFormat = format->chroma_format; createInfo.OutputFormat = cudaVideoSurfaceFormat_NV12; createInfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Adaptive; createInfo.ulTargetWidth = format->display_area.right; createInfo.ulTargetHeight = format->display_area.bottom; createInfo.ulNumOutputSurfaces = 2; CUvideodecoder decoder; cuvidCreateDecoder(&decoder, &createInfo); return 1; // Return number of decode surfaces }
Process video frames with CUDA:
c// Map decoded frame to CUDA CUVIDPROCPARAMS procParams = {}; procParams.progressive_frame = 1; procParams.output_stream = cudaStream; unsigned int pitch; CUdeviceptr framePtr; cuvidMapVideoFrame(decoder, pictureIndex, &framePtr, &pitch, &procParams); // Process with CUDA kernel processFrameKernel<<<blocks, threads, 0, cudaStream>>>( (unsigned char*)framePtr, pitch, width, height); // Unmap cuvidUnmapVideoFrame(decoder, framePtr); // For encoding: register CUDA resource NV_ENC_REGISTER_RESOURCE registerResource = {NV_ENC_REGISTER_RESOURCE_VER}; registerResource.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; registerResource.resourceToRegister = (void*)cudaFrame; registerResource.width = width; registerResource.height = height; registerResource.pitch = pitch; registerResource.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12; registerResource.bufferUsage = NV_ENC_INPUT_IMAGE; nvenc.nvEncRegisterResource(encoder, ®isterResource);
Submit frames for encoding:
c// Map input buffer NV_ENC_MAP_INPUT_RESOURCE mapInput = {NV_ENC_MAP_INPUT_RESOURCE_VER}; mapInput.registeredResource = registeredResource; nvenc.nvEncMapInputResource(encoder, &mapInput); // Configure picture parameters NV_ENC_PIC_PARAMS picParams = {NV_ENC_PIC_PARAMS_VER}; picParams.inputBuffer = mapInput.mappedResource; picParams.bufferFmt = mapInput.mappedBufferFmt; picParams.inputWidth = width; picParams.inputHeight = height; picParams.outputBitstream = bitstreamBuffer; picParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; picParams.inputTimeStamp = frameNumber; // Encode nvenc.nvEncEncodePicture(encoder, &picParams); // Lock and retrieve bitstream NV_ENC_LOCK_BITSTREAM lockBitstream = {NV_ENC_LOCK_BITSTREAM_VER}; lockBitstream.outputBitstream = bitstreamBuffer; nvenc.nvEncLockBitstream(encoder, &lockBitstream); // Copy encoded data memcpy(outputBuffer, lockBitstream.bitstreamBufferPtr, lockBitstream.bitstreamSizeInBytes); nvenc.nvEncUnlockBitstream(encoder, bitstreamBuffer); nvenc.nvEncUnmapInputResource(encoder, mapInput.mappedResource);
Handle multiple encode sessions:
c// Query max encode sessions NV_ENC_CAPS_PARAM capsParam = {NV_ENC_CAPS_PARAM_VER}; capsParam.capsToQuery = NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS; // Create multiple encoders for concurrent encoding std::vector<void*> encoders(numStreams); for (int i = 0; i < numStreams; i++) { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS sessionParams = { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER}; sessionParams.device = cudaDevice; sessionParams.deviceType = NV_ENC_DEVICE_TYPE_CUDA; nvenc.nvEncOpenEncodeSessionEx(&sessionParams, &encoders[i]); } // Encode streams in parallel using CUDA streams for (int i = 0; i < numStreams; i++) { // Each encoder uses its own CUDA stream cudaStreamCreate(&streams[i]); // Submit frames asynchronously }
Use NVENC with FFmpeg:
bash# Encode with NVENC ffmpeg -hwaccel cuda -hwaccel_output_format cuda \ -i input.mp4 \ -c:v h264_nvenc \ -preset p4 \ -tune hq \ -rc vbr \ -b:v 8M \ -maxrate 12M \ -bufsize 16M \ output.mp4 # HEVC encoding ffmpeg -hwaccel cuda -i input.mp4 \ -c:v hevc_nvenc \ -preset p7 \ -rc constqp \ -qp 23 \ output_hevc.mp4 # Decode with NVDEC, process, encode with NVENC ffmpeg -hwaccel cuda -hwaccel_output_format cuda \ -i input.mp4 \ -vf "scale_cuda=1280:720" \ -c:v h264_nvenc \ output_720p.mp4 # AV1 encoding (RTX 40 series) ffmpeg -hwaccel cuda -i input.mp4 \ -c:v av1_nvenc \ -preset p4 \ -b:v 5M \ output_av1.mp4
This skill integrates with the following processes:
gpu-image-video-processing.js - Video processing workflowsjson{ "operation": "encode-session", "status": "success", "configuration": { "codec": "H.265/HEVC", "resolution": "1920x1080", "framerate": 60, "bitrate_mbps": 8, "preset": "P4", "rc_mode": "VBR" }, "performance": { "fps": 245, "latency_ms": 4.1, "gpu_utilization_pct": 35 }, "output": { "format": "HEVC", "file": "output.hevc", "size_mb": 125.4 } }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 29,019 | 22,603 | -22% | 1 | 1 | 0% | 4,763 | 5,535 | +16% | 0 | 0 | — |
case-02 | fail→pass | 21,627 | 17,968 | -17% | 1 | 1 | 0% | 4,245 | 5,997 | +41% | 0 | 0 | — |
case-03 | fail→pass | 18,642 | 11,261 | -40% | 1 | 1 | 0% | 2,860 | 5,506 | +93% | 0 | 0 | — |
case-04 | pass→pass | 10,929 | 9,626 | -12% | 1 | 1 | 0% | 2,118 | 4,965 | +134% | 0 | 0 | — |
case-05 | fail→pass | 13,588 | 6,894 | -49% | 1 | 1 | 0% | 2,023 | 4,511 | +123% | 0 | 0 | — |
case-06 | pass→pass | 5,301 | 4,394 | -17% | 1 | 1 | 0% | 1,143 | 4,060 | +255% | 0 | 0 | — |
case-07 | pass→pass | 11,179 | 10,841 | -3% | 1 | 1 | 0% | 2,167 | 5,149 | +138% | 0 | 0 | — |
case-08 | pass→pass | 7,975 | 8,453 | +6% | 1 | 1 | 0% | 1,500 | 4,422 | +195% | 0 | 0 | — |
case-09 | pass→pass | 10,905 | 11,221 | +3% | 1 | 1 | 0% | 2,255 | 5,243 | +133% | 0 | 0 | — |
case-10 | pass→pass | 9,580 | 5,733 | -40% | 1 | 1 | 0% | 2,016 | 4,224 | +110% | 0 | 0 | — |
case-11 | pass→pass | 7,148 | 3,898 | -45% | 1 | 1 | 0% | 1,033 | 3,976 | +285% | 0 | 0 | — |
case-12 | fail→pass | 6,662 | 6,331 | -5% | 1 | 1 | 0% | 1,151 | 4,286 | +272% | 0 | 0 | — |
case-13 | pass→pass | 10,436 | 7,968 | -24% | 1 | 1 | 0% | 1,790 | 4,241 | +137% | 0 | 0 | — |
case-14 | pass→pass | 6,288 | 5,605 | -11% | 1 | 1 | 0% | 1,062 | 3,916 | +269% | 0 | 0 | — |
case-15 | pass→pass | 15,377 | 14,239 | -7% | 1 | 1 | 0% | 2,765 | 5,738 | +108% | 0 | 0 | — |
case-16 | pass→pass | 11,352 | 5,879 | -48% | 1 | 1 | 0% | 1,894 | 4,263 | +125% | 0 | 0 | — |
case-17 | pass→pass | 8,399 | 5,133 | -39% | 1 | 1 | 0% | 1,244 | 4,046 | +225% | 0 | 0 | — |
case-18 | pass→pass | 15,435 | 12,124 | -21% | 1 | 1 | 0% | 2,286 | 4,958 | +117% | 0 | 0 | — |
case-19 | pass→pass | 12,733 | 11,871 | -7% | 1 | 1 | 0% | 1,470 | 4,832 | +229% | 0 | 0 | — |
case-20 | pass→pass | 16,253 | 15,283 | -6% | 1 | 1 | 0% | 2,359 | 5,534 | +135% | 0 | 0 | — |
case-21 | fail→pass | 23,411 | 21,213 | -9% | 1 | 1 | 0% | 3,615 | 6,171 | +71% | 0 | 0 | — |
case-22 | pass→pass | 29,808 | 29,472 | -1% | 1 | 1 | 0% | 3,717 | 7,638 | +105% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.