如何将FFmpeg AVFrame中的CUdeviceptr平面复制到自定义CUDA内存?
FFmpeg CUDA解码帧复制到自定义CUDA内存失败问题排查
问题现象
将FFmpeg(CUDA)解码得到的帧平面复制到自定义CUDA内存时,cuMemcpyDtoD_v2始终返回ErrorInvalidValue,提示AVFrame.data[0]对应的CUdeviceptr无效;已创建并设置CUDA上下文,但cuCtxPushCurrent_v2或cuCtxSetCurrent均无法解决问题。
排查与解决步骤
1. 强制复用FFmpeg的CUDA上下文
FFmpeg初始化CUDA解码器时会创建独立的CUDA上下文,自定义内存分配必须在同一个上下文下进行,否则设备指针无法跨上下文访问:
- 从FFmpeg的硬件设备上下文中提取CUDA上下文:
// 假设已初始化好解码器的hw_device_ctx CUcontext ffmpeg_cuda_ctx; // 通过AVHWDeviceContext提取底层CUDA上下文 AVHWDeviceContext *hw_ctx = (AVHWDeviceContext*)codec_ctx->hw_device_ctx->data; CUcontext* ctx_ptr = (CUcontext*)hw_ctx->hwctx; ffmpeg_cuda_ctx = *ctx_ptr; // 将FFmpeg的上下文设为当前,再执行内存分配和复制操作 cuCtxSetCurrent(ffmpeg_cuda_ctx);
- 禁止自行创建新的CUDA上下文,否则会导致上下文不匹配,触发
ErrorInvalidValue。
2. 正确提取CUDA帧的设备指针
AV_PIX_FMT_CUDA格式的AVFrame中,data[n]直接对应CUdeviceptr,无需通过av_frame_get_plane_buffer提取:
// 确保avFrame的格式是AV_PIX_FMT_CUDA if (avFrame->format != AV_PIX_FMT_CUDA) { // 处理错误:当前帧不是CUDA硬件帧 } // 直接从data字段获取源指针 CUdeviceptr srcPtr = (CUdeviceptr)avFrame->data[0];
av_frame_get_plane_buffer仅适用于CPU内存帧,对CUDA硬件帧调用会返回错误的内存信息,导致后续复制失败。
3. 验证内存大小匹配
目标内存的分配大小必须与源帧平面的实际大小一致:
- 计算CUDA帧平面的正确大小:
// 以Y平面为例,linesize[0]是每行字节数,height是帧高度 size_t plane_size = (size_t)avFrame->linesize[0] * avFrame->height; // 分配目标内存时使用该大小 cuMemAlloc_v2(ref dstPtr, plane_size);
避免使用plane->size(来自av_frame_get_plane_buffer),该值对CUDA帧无效。
4. 输出详细错误信息
通过cuGetErrorString获取错误的具体描述,辅助定位问题:
CUResult error = cuMemcpyDtoD_v2(dstPtr, srcPtr, plane_size); if (error != CUDA_SUCCESS) { const char* err_msg; cuGetErrorString(error, &err_msg); fprintf(stderr, "CUDA复制错误: %s\n", err_msg); }
5. 确认FFmpeg CUDA解码器初始化正确
确保解码器已正确关联硬件加速上下文:
// 创建CUDA硬件设备上下文 AVBufferRef* hw_device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA); if (!hw_device_ctx) { // 处理分配失败 } // 初始化硬件上下文(需传入CUDA设备ID等参数) if (av_hwdevice_ctx_init(hw_device_ctx) < 0) { // 处理初始化失败 } // 将硬件上下文关联到解码器 codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
解码后的AVFrame必须满足avFrame->hw_frames_ctx != NULL,否则说明未成功解码为CUDA硬件帧。
内容的提问来源于stack exchange,提问作者SexyBoooom
相关产品推荐
相关产品推荐

