static int hwmap_config_output(AVFilterLink *outlink) { AVFilterContext *avctx = outlink->src; HWMapContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; AVHWFramesContext *hwfc; AVBufferRef *device; const AVPixFmtDescriptor *desc; int err; av_log(avctx, AV_LOG_DEBUG, "Configure hwmap %s -> %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(outlink->format)); av_buffer_unref(&ctx->hwframes_ref); device = avctx->hw_device_ctx; if (inlink->hw_frames_ctx) { hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data; if (ctx->derive_device_type) { enum AVHWDeviceType type; type = av_hwdevice_find_type_by_name(ctx->derive_device_type); if (type == AV_HWDEVICE_TYPE_NONE) { av_log(avctx, AV_LOG_ERROR, "Invalid device type.\n"); goto fail; } err = av_hwdevice_ctx_create_derived(&device, type, hwfc->device_ref, 0); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to created derived " "device context: %d.\n", err); goto fail; } } desc = av_pix_fmt_desc_get(outlink->format); if (!desc) { err = AVERROR(EINVAL); goto fail; } if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) && !ctx->reverse) { // Map between two hardware formats (including the case of // undoing an existing mapping). if (!device) { av_log(avctx, AV_LOG_ERROR, "A device reference is " "required to map to a hardware format.\n"); err = AVERROR(EINVAL); goto fail; } err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, device, inlink->hw_frames_ctx, 0); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create derived " "frames context: %d.\n", err); goto fail; } } else if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) && ctx->reverse) { // Map between two hardware formats, but do it in reverse. // Make a new hwframe context for the target type, and then // overwrite the input hwframe context with a derived context // mapped from that back to the source type. AVBufferRef *source; AVHWFramesContext *frames; ctx->hwframes_ref = av_hwframe_ctx_alloc(device); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } frames = (AVHWFramesContext*)ctx->hwframes_ref->data; frames->format = outlink->format; frames->sw_format = hwfc->sw_format; frames->width = hwfc->width; frames->height = hwfc->height; frames->initial_pool_size = 64; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise " "target frames context: %d.\n", err); goto fail; } err = av_hwframe_ctx_create_derived(&source, inlink->format, hwfc->device_ref, ctx->hwframes_ref, ctx->mode); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create " "derived source frames context: %d.\n", err); goto fail; } // Here is the naughty bit. This overwriting changes what // ff_get_video_buffer() in the previous filter returns - // it will now give a frame allocated here mapped back to // the format it expects. If there were any additional // constraints on the output frames there then this may // break nastily. av_buffer_unref(&inlink->hw_frames_ctx); inlink->hw_frames_ctx = source; } else if ((outlink->format == hwfc->format && inlink->format == hwfc->sw_format) || inlink->format == hwfc->format) { // Map from a hardware format to a software format, or // undo an existing such mapping. ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } } else { // Non-matching formats - not supported. av_log(avctx, AV_LOG_ERROR, "Unsupported formats for " "hwmap: from %s (%s) to %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(hwfc->format), av_get_pix_fmt_name(outlink->format)); err = AVERROR(EINVAL); goto fail; } } else if (avctx->hw_device_ctx) { // Map from a software format to a hardware format. This // creates a new hwframe context like hwupload, but then // returns frames mapped from that to the previous link in // order to fill them without an additional copy. if (!device) { av_log(avctx, AV_LOG_ERROR, "A device reference is " "required to create new frames with reverse " "mapping.\n"); err = AVERROR(EINVAL); goto fail; } ctx->reverse = 1; ctx->hwframes_ref = av_hwframe_ctx_alloc(device); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data; hwfc->format = outlink->format; hwfc->sw_format = inlink->format; hwfc->width = inlink->w; hwfc->height = inlink->h; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create frame " "context for reverse mapping: %d.\n", err); goto fail; } } else { av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware " "context (a device, or frames on input).\n"); return AVERROR(EINVAL); } outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); if (!outlink->hw_frames_ctx) { err = AVERROR(ENOMEM); goto fail; } outlink->w = inlink->w; outlink->h = inlink->h; return 0; fail: av_buffer_unref(&ctx->hwframes_ref); return err; }
static int hwmap_config_output(AVFilterLink *outlink) { AVFilterContext *avctx = outlink->src; HWMapContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; AVHWFramesContext *hwfc; const AVPixFmtDescriptor *desc; int err; av_log(avctx, AV_LOG_DEBUG, "Configure hwmap %s -> %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(outlink->format)); if (inlink->hw_frames_ctx) { hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data; desc = av_pix_fmt_desc_get(outlink->format); if (!desc) return AVERROR(EINVAL); if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { // Map between two hardware formats (including the case of // undoing an existing mapping). ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx); if (!ctx->hwdevice_ref) { err = AVERROR(ENOMEM); goto fail; } err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, ctx->hwdevice_ref, inlink->hw_frames_ctx, 0); if (err < 0) goto fail; } else if ((outlink->format == hwfc->format && inlink->format == hwfc->sw_format) || inlink->format == hwfc->format) { // Map from a hardware format to a software format, or // undo an existing such mapping. ctx->hwdevice_ref = NULL; ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } } else { // Non-matching formats - not supported. av_log(avctx, AV_LOG_ERROR, "Unsupported formats for " "hwmap: from %s (%s) to %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(hwfc->format), av_get_pix_fmt_name(outlink->format)); err = AVERROR(EINVAL); goto fail; } } else if (avctx->hw_device_ctx) { // Map from a software format to a hardware format. This // creates a new hwframe context like hwupload, but then // returns frames mapped from that to the previous link in // order to fill them without an additional copy. ctx->map_backwards = 1; ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx); if (!ctx->hwdevice_ref) { err = AVERROR(ENOMEM); goto fail; } ctx->hwframes_ref = av_hwframe_ctx_alloc(ctx->hwdevice_ref); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data; hwfc->format = outlink->format; hwfc->sw_format = inlink->format; hwfc->width = inlink->w; hwfc->height = inlink->h; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create frame " "context for backward mapping: %d.\n", err); goto fail; } } else { av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware " "context (a device, or frames on input).\n"); return AVERROR(EINVAL); } outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); if (!outlink->hw_frames_ctx) { err = AVERROR(ENOMEM); goto fail; } outlink->w = inlink->w; outlink->h = inlink->h; return 0; fail: av_buffer_unref(&ctx->hwframes_ref); av_buffer_unref(&ctx->hwdevice_ref); return err; }