static int get_free_frame(QSVEncContext *q, QSVFrame **f) { QSVFrame *frame, **last; clear_unused_frames(q); frame = q->work_frames; last = &q->work_frames; while (frame) { if (!frame->surface) { *f = frame; return 0; } last = &frame->next; frame = frame->next; } frame = av_mallocz(sizeof(*frame)); if (!frame) return AVERROR(ENOMEM); frame->frame = av_frame_alloc(); if (!frame->frame) { av_freep(&frame); return AVERROR(ENOMEM); } *last = frame; *f = frame; return 0; }
/* get the output surface */ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; QSVFrame *out_frame; int ret; clear_unused_frames(s->out_frame_list); out_frame = get_free_frame(&s->out_frame_list); if (!out_frame) return NULL; /* For video memory, get a hw frame; * For system memory, get a sw frame and map it into a mfx_surface. */ if (!IS_SYSTEM_MEMORY(s->out_mem_mode)) { out_frame->frame = av_frame_alloc(); if (!out_frame->frame) return NULL; ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n"); return NULL; } out_frame->surface = (mfxFrameSurface1 *)out_frame->frame->data[3]; } else { /* Get a frame with aligned dimensions. * Libmfx need system memory being 128x64 aligned */ out_frame->frame = ff_get_video_buffer(outlink, FFALIGN(outlink->w, 128), FFALIGN(outlink->h, 64)); if (!out_frame->frame) return NULL; out_frame->frame->width = outlink->w; out_frame->frame->height = outlink->h; ret = map_frame_to_surface(out_frame->frame, &out_frame->surface_internal); if (ret < 0) return NULL; out_frame->surface = &out_frame->surface_internal; } out_frame->surface->Info = s->vpp_param.vpp.Out; return out_frame; }
/* get the input surface */ static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) { QSVFrame *qsv_frame; AVFilterContext *ctx = inlink->dst; clear_unused_frames(s->in_frame_list); qsv_frame = get_free_frame(&s->in_frame_list); if (!qsv_frame) return NULL; /* Turn AVFrame into mfxFrameSurface1. * For video/opaque memory mode, pix_fmt is AV_PIX_FMT_QSV, and * mfxFrameSurface1 is stored in AVFrame->data[3]; * for system memory mode, raw video data is stored in * AVFrame, we should map it into mfxFrameSurface1. */ if (!IS_SYSTEM_MEMORY(s->in_mem_mode)) { if (picref->format != AV_PIX_FMT_QSV) { av_log(ctx, AV_LOG_ERROR, "QSVVPP gets a wrong frame.\n"); return NULL; } qsv_frame->frame = av_frame_clone(picref); qsv_frame->surface = (mfxFrameSurface1 *)qsv_frame->frame->data[3]; } else { /* make a copy if the input is not padded as libmfx requires */ if (picref->height & 31 || picref->linesize[0] & 31) { qsv_frame->frame = ff_get_video_buffer(inlink, FFALIGN(inlink->w, 32), FFALIGN(inlink->h, 32)); if (!qsv_frame->frame) return NULL; qsv_frame->frame->width = picref->width; qsv_frame->frame->height = picref->height; if (av_frame_copy(qsv_frame->frame, picref) < 0) { av_frame_free(&qsv_frame->frame); return NULL; } av_frame_copy_props(qsv_frame->frame, picref); av_frame_free(&picref); } else qsv_frame->frame = av_frame_clone(picref); if (map_frame_to_surface(qsv_frame->frame, &qsv_frame->surface_internal) < 0) { av_log(ctx, AV_LOG_ERROR, "Unsupported frame.\n"); return NULL; } qsv_frame->surface = &qsv_frame->surface_internal; } qsv_frame->surface->Info = s->frame_infos[FF_INLINK_IDX(inlink)]; qsv_frame->surface->Data.TimeStamp = av_rescale_q(qsv_frame->frame->pts, inlink->time_base, default_tb); qsv_frame->surface->Info.PicStruct = !qsv_frame->frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE : (qsv_frame->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : MFX_PICSTRUCT_FIELD_BFF); if (qsv_frame->frame->repeat_pict == 1) qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED; else if (qsv_frame->frame->repeat_pict == 2) qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING; else if (qsv_frame->frame->repeat_pict == 4) qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING; return qsv_frame; }