static int cuda_frames_init(AVHWFramesContext *ctx) { CUDAFramesContext *priv = ctx->internal->priv; int aligned_width = FFALIGN(ctx->width, CUDA_FRAME_ALIGNMENT); int i; for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { if (ctx->sw_format == supported_formats[i]) break; } if (i == FF_ARRAY_ELEMS(supported_formats)) { av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n", av_get_pix_fmt_name(ctx->sw_format)); return AVERROR(ENOSYS); } av_pix_fmt_get_chroma_sub_sample(ctx->sw_format, &priv->shift_width, &priv->shift_height); if (!ctx->pool) { int size; switch (ctx->sw_format) { case AV_PIX_FMT_NV12: case AV_PIX_FMT_YUV420P: size = aligned_width * ctx->height * 3 / 2; break; case AV_PIX_FMT_YUV444P: case AV_PIX_FMT_P010: case AV_PIX_FMT_P016: size = aligned_width * ctx->height * 3; break; case AV_PIX_FMT_YUV444P16: size = aligned_width * ctx->height * 6; break; default: av_log(ctx, AV_LOG_ERROR, "BUG: Pixel format missing from size calculation."); return AVERROR_BUG; } ctx->internal->pool_internal = av_buffer_pool_init2(size, ctx, cuda_pool_alloc, NULL); if (!ctx->internal->pool_internal) return AVERROR(ENOMEM); } return 0; }
static int vdpau_frames_init(AVHWFramesContext *ctx) { VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv; VDPAUFramesContext *priv = ctx->internal->priv; int i; switch (ctx->sw_format) { case AV_PIX_FMT_YUV420P: priv->chroma_type = VDP_CHROMA_TYPE_420; break; case AV_PIX_FMT_YUV422P: priv->chroma_type = VDP_CHROMA_TYPE_422; break; case AV_PIX_FMT_YUV444P: priv->chroma_type = VDP_CHROMA_TYPE_444; break; default: av_log(ctx, AV_LOG_ERROR, "Unsupported data layout: %s\n", av_get_pix_fmt_name(ctx->sw_format)); return AVERROR(ENOSYS); } for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) { if (vdpau_pix_fmts[i].chroma_type == priv->chroma_type) { priv->chroma_idx = i; priv->pix_fmts = device_priv->pix_fmts[i]; priv->nb_pix_fmts = device_priv->nb_pix_fmts[i]; break; } } if (!priv->pix_fmts) { av_log(ctx, AV_LOG_ERROR, "Unsupported chroma type: %d\n", priv->chroma_type); return AVERROR(ENOSYS); } if (!ctx->pool) { ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(VdpVideoSurface), ctx, vdpau_pool_alloc, NULL); if (!ctx->internal->pool_internal) return AVERROR(ENOMEM); } priv->get_data = device_priv->get_data; priv->put_data = device_priv->put_data; return 0; }
static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc) { QSVFramesContext *s = ctx->internal->priv; AVQSVFramesContext *frames_hwctx = ctx->hwctx; int i, ret = 0; if (ctx->initial_pool_size <= 0) { av_log(ctx, AV_LOG_ERROR, "QSV requires a fixed frame pool size\n"); return AVERROR(EINVAL); } s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, sizeof(*s->surfaces_internal)); if (!s->surfaces_internal) return AVERROR(ENOMEM); for (i = 0; i < ctx->initial_pool_size; i++) { ret = qsv_init_surface(ctx, &s->surfaces_internal[i]); if (ret < 0) return ret; } if (!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME)) { ret = qsv_init_child_ctx(ctx); if (ret < 0) return ret; } ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(mfxFrameSurface1), ctx, qsv_pool_alloc, NULL); if (!ctx->internal->pool_internal) return AVERROR(ENOMEM); frames_hwctx->surfaces = s->surfaces_internal; frames_hwctx->nb_surfaces = ctx->initial_pool_size; return 0; }
static int dxva2_init_pool(AVHWFramesContext *ctx) { AVDXVA2FramesContext *frames_hwctx = ctx->hwctx; AVDXVA2DeviceContext *device_hwctx = ctx->device_ctx->hwctx; DXVA2FramesContext *s = ctx->internal->priv; int decode = (frames_hwctx->surface_type == DXVA2_VideoDecoderRenderTarget); int i; HRESULT hr; if (ctx->initial_pool_size <= 0) return 0; hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, &s->device_handle); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n"); return AVERROR_UNKNOWN; } hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, s->device_handle, decode ? &video_decoder_service : &video_processor_service, (void **)&s->service); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Failed to create the video service\n"); return AVERROR_UNKNOWN; } for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { if (ctx->sw_format == supported_formats[i].pix_fmt) { s->format = supported_formats[i].d3d_format; break; } } if (i == FF_ARRAY_ELEMS(supported_formats)) { av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", av_get_pix_fmt_name(ctx->sw_format)); return AVERROR(EINVAL); } s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, sizeof(*s->surfaces_internal)); if (!s->surfaces_internal) return AVERROR(ENOMEM); hr = IDirectXVideoAccelerationService_CreateSurface(s->service, ctx->width, ctx->height, ctx->initial_pool_size - 1, s->format, D3DPOOL_DEFAULT, 0, frames_hwctx->surface_type, s->surfaces_internal, NULL); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Could not create the surfaces\n"); return AVERROR_UNKNOWN; } ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(*s->surfaces_internal), ctx, dxva2_pool_alloc, NULL); if (!ctx->internal->pool_internal) return AVERROR(ENOMEM); frames_hwctx->surfaces = s->surfaces_internal; frames_hwctx->nb_surfaces = ctx->initial_pool_size; return 0; }
int ff_nvdec_decode_init(AVCodecContext *avctx) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; NVDECFramePool *pool; AVHWFramesContext *frames_ctx; const AVPixFmtDescriptor *sw_desc; CUVIDDECODECREATEINFO params = { 0 }; int cuvid_codec_type, cuvid_chroma_format; int ret = 0; sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); if (!sw_desc) return AVERROR_BUG; cuvid_codec_type = map_avcodec_id(avctx->codec_id); if (cuvid_codec_type < 0) { av_log(avctx, AV_LOG_ERROR, "Unsupported codec ID\n"); return AVERROR_BUG; } cuvid_chroma_format = map_chroma_format(avctx->sw_pix_fmt); if (cuvid_chroma_format < 0) { av_log(avctx, AV_LOG_ERROR, "Unsupported chroma format\n"); return AVERROR(ENOSYS); } if (!avctx->hw_frames_ctx) { ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_CUDA); if (ret < 0) return ret; } frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; params.ulWidth = avctx->coded_width; params.ulHeight = avctx->coded_height; params.ulTargetWidth = avctx->coded_width; params.ulTargetHeight = avctx->coded_height; params.bitDepthMinus8 = sw_desc->comp[0].depth - 8; params.OutputFormat = params.bitDepthMinus8 ? cudaVideoSurfaceFormat_P016 : cudaVideoSurfaceFormat_NV12; params.CodecType = cuvid_codec_type; params.ChromaFormat = cuvid_chroma_format; params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size; params.ulNumOutputSurfaces = frames_ctx->initial_pool_size; ret = nvdec_decoder_create(&ctx->decoder_ref, frames_ctx->device_ref, ¶ms, avctx); if (ret < 0) { if (params.ulNumDecodeSurfaces > 32) { av_log(avctx, AV_LOG_WARNING, "Using more than 32 (%d) decode surfaces might cause nvdec to fail.\n", (int)params.ulNumDecodeSurfaces); av_log(avctx, AV_LOG_WARNING, "Try lowering the amount of threads. Using %d right now.\n", avctx->thread_count); } return ret; } pool = av_mallocz(sizeof(*pool)); if (!pool) { ret = AVERROR(ENOMEM); goto fail; } pool->dpb_size = frames_ctx->initial_pool_size; ctx->decoder_pool = av_buffer_pool_init2(sizeof(int), pool, nvdec_decoder_frame_alloc, av_free); if (!ctx->decoder_pool) { ret = AVERROR(ENOMEM); goto fail; } return 0; fail: ff_nvdec_decode_uninit(avctx); return ret; }
static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc) { QSVFramesContext *s = ctx->internal->priv; AVQSVFramesContext *frames_hwctx = ctx->hwctx; const AVPixFmtDescriptor *desc; int i, ret = 0; desc = av_pix_fmt_desc_get(ctx->sw_format); if (!desc) return AVERROR_BUG; if (ctx->initial_pool_size <= 0) { av_log(ctx, AV_LOG_ERROR, "QSV requires a fixed frame pool size\n"); return AVERROR(EINVAL); } s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, sizeof(*s->surfaces_internal)); if (!s->surfaces_internal) return AVERROR(ENOMEM); for (i = 0; i < ctx->initial_pool_size; i++) { mfxFrameSurface1 *surf = &s->surfaces_internal[i]; surf->Info.BitDepthLuma = desc->comp[0].depth; surf->Info.BitDepthChroma = desc->comp[0].depth; surf->Info.Shift = desc->comp[0].depth > 8; if (desc->log2_chroma_w && desc->log2_chroma_h) surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV420; else if (desc->log2_chroma_w) surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV422; else surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV444; surf->Info.FourCC = fourcc; surf->Info.Width = ctx->width; surf->Info.CropW = ctx->width; surf->Info.Height = ctx->height; surf->Info.CropH = ctx->height; surf->Info.FrameRateExtN = 25; surf->Info.FrameRateExtD = 1; } if (!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME)) { ret = qsv_init_child_ctx(ctx); if (ret < 0) return ret; } ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(mfxFrameSurface1), ctx, qsv_pool_alloc, NULL); if (!ctx->internal->pool_internal) return AVERROR(ENOMEM); frames_hwctx->surfaces = s->surfaces_internal; frames_hwctx->nb_surfaces = ctx->initial_pool_size; return 0; }
static int vaapi_frames_init(AVHWFramesContext *hwfc) { AVVAAPIFramesContext *avfc = hwfc->hwctx; VAAPIFramesContext *ctx = hwfc->internal->priv; AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; VAImageFormat *expected_format; AVBufferRef *test_surface = NULL; VASurfaceID test_surface_id; VAImage test_image; VAStatus vas; int err, i; unsigned int fourcc, rt_format; for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) { if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) { fourcc = vaapi_format_map[i].fourcc; rt_format = vaapi_format_map[i].rt_format; break; } } if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) { av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", av_get_pix_fmt_name(hwfc->sw_format)); return AVERROR(EINVAL); } if (!hwfc->pool) { int need_memory_type = 1, need_pixel_format = 1; for (i = 0; i < avfc->nb_attributes; i++) { if (ctx->attributes[i].type == VASurfaceAttribMemoryType) need_memory_type = 0; if (ctx->attributes[i].type == VASurfaceAttribPixelFormat) need_pixel_format = 0; } ctx->nb_attributes = avfc->nb_attributes + need_memory_type + need_pixel_format; ctx->attributes = av_malloc(ctx->nb_attributes * sizeof(*ctx->attributes)); if (!ctx->attributes) { err = AVERROR(ENOMEM); goto fail; } for (i = 0; i < avfc->nb_attributes; i++) ctx->attributes[i] = avfc->attributes[i]; if (need_memory_type) { ctx->attributes[i++] = (VASurfaceAttrib) { .type = VASurfaceAttribMemoryType, .flags = VA_SURFACE_ATTRIB_SETTABLE, .value.type = VAGenericValueTypeInteger, .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA, }; } if (need_pixel_format) { ctx->attributes[i++] = (VASurfaceAttrib) { .type = VASurfaceAttribPixelFormat, .flags = VA_SURFACE_ATTRIB_SETTABLE, .value.type = VAGenericValueTypeInteger, .value.value.i = fourcc, }; } av_assert0(i == ctx->nb_attributes); ctx->rt_format = rt_format; if (hwfc->initial_pool_size > 0) { // This pool will be usable as a render target, so we need to store // all of the surface IDs somewhere that vaCreateContext() calls // will be able to access them. avfc->nb_surfaces = 0; avfc->surface_ids = av_malloc(hwfc->initial_pool_size * sizeof(*avfc->surface_ids)); if (!avfc->surface_ids) { err = AVERROR(ENOMEM); goto fail; } } else { // This pool allows dynamic sizing, and will not be usable as a // render target. avfc->nb_surfaces = 0; avfc->surface_ids = NULL; } hwfc->internal->pool_internal = av_buffer_pool_init2(sizeof(VASurfaceID), hwfc, &vaapi_pool_alloc, NULL); if (!hwfc->internal->pool_internal) { av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n"); err = AVERROR(ENOMEM); goto fail; } } // Allocate a single surface to test whether vaDeriveImage() is going // to work for the specific configuration. if (hwfc->pool) { test_surface = av_buffer_pool_get(hwfc->pool); if (!test_surface) { av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " "user-configured buffer pool.\n"); err = AVERROR(ENOMEM); goto fail; } } else { test_surface = av_buffer_pool_get(hwfc->internal->pool_internal); if (!test_surface) { av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " "internal buffer pool.\n"); err = AVERROR(ENOMEM); goto fail; } } test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data; ctx->derive_works = 0; err = vaapi_get_image_format(hwfc->device_ctx, hwfc->sw_format, &expected_format); if (err == 0) { vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image); if (vas == VA_STATUS_SUCCESS) { if (expected_format->fourcc == test_image.format.fourcc) { av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n"); ctx->derive_works = 1; } else { av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " "derived image format %08x does not match " "expected format %08x.\n", expected_format->fourcc, test_image.format.fourcc); } vaDestroyImage(hwctx->display, test_image.image_id); } else { av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " "deriving image does not work: " "%d (%s).\n", vas, vaErrorStr(vas)); } } else { av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " "image format is not supported.\n"); } av_buffer_unref(&test_surface); return 0; fail: av_buffer_unref(&test_surface); av_freep(&avfc->surface_ids); av_freep(&ctx->attributes); return err; } static void vaapi_frames_uninit(AVHWFramesContext *hwfc) { AVVAAPIFramesContext *avfc = hwfc->hwctx; VAAPIFramesContext *ctx = hwfc->internal->priv; av_freep(&avfc->surface_ids); av_freep(&ctx->attributes); }