int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q) { mfxVideoParam param = { { 0 } }; int ret; q->iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->iopattern = qsv->iopattern; q->ext_buffers = qsv->ext_buffers; q->nb_ext_buffers = qsv->nb_ext_buffers; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL); if (ret < 0) return ret; q->session = q->internal_qs.session; } ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); if (ret < 0) return ret; param.mfx.CodecId = ret; param.mfx.CodecProfile = avctx->profile; param.mfx.CodecLevel = avctx->level; param.mfx.FrameInfo.BitDepthLuma = 8; param.mfx.FrameInfo.BitDepthChroma = 8; param.mfx.FrameInfo.Shift = 0; param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; param.mfx.FrameInfo.Width = avctx->coded_width; param.mfx.FrameInfo.Height = avctx->coded_height; param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; param.IOPattern = q->iopattern; param.AsyncDepth = q->async_depth; param.ExtParam = q->ext_buffers; param.NumExtParam = q->nb_ext_buffers; ret = MFXVideoDECODE_Init(q->session, ¶m); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder\n"); return ff_qsv_error(ret); } return 0; }
static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session, AVBufferRef *hw_frames_ref) { int ret; if (session) { q->session = session; } else if (hw_frames_ref) { if (q->internal_session) { MFXClose(q->internal_session); q->internal_session = NULL; } av_buffer_unref(&q->frames_ctx.hw_frames_ctx); q->frames_ctx.hw_frames_ctx = av_buffer_ref(hw_frames_ref); if (!q->frames_ctx.hw_frames_ctx) return AVERROR(ENOMEM); ret = ff_qsv_init_session_hwcontext(avctx, &q->internal_session, &q->frames_ctx, q->load_plugins, q->iopattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY); if (ret < 0) { av_buffer_unref(&q->frames_ctx.hw_frames_ctx); return ret; } q->session = q->internal_session; } else { if (!q->internal_session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_session, q->load_plugins); if (ret < 0) return ret; } q->session = q->internal_session; } /* make sure the decoder is uninitialized */ MFXVideoDECODE_Close(q->session); return 0; }
static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session) { if (!session) { if (!q->internal_session) { int ret = ff_qsv_init_internal_session(avctx, &q->internal_session); if (ret < 0) return ret; } q->session = q->internal_session; } else { q->session = session; } /* make sure the decoder is uninitialized */ MFXVideoDECODE_Close(q->session); return 0; }
static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) { uint8_t sps_buf[128]; uint8_t pps_buf[128]; mfxExtCodingOptionSPSPPS extradata = { .Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS, .Header.BufferSz = sizeof(extradata), .SPSBuffer = sps_buf, .SPSBufSize = sizeof(sps_buf), .PPSBuffer = pps_buf, .PPSBufSize = sizeof(pps_buf) }; mfxExtBuffer *ext_buffers[] = { (mfxExtBuffer*)&extradata, }; int need_pps = avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO; int ret; q->param.ExtParam = ext_buffers; q->param.NumExtParam = FF_ARRAY_ELEMS(ext_buffers); ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); if (ret < 0) return ff_qsv_error(ret); q->packet_size = q->param.mfx.BufferSizeInKB * 1000; if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize)) { av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx.\n"); return AVERROR_UNKNOWN; } avctx->extradata = av_malloc(extradata.SPSBufSize + need_pps * extradata.PPSBufSize + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) return AVERROR(ENOMEM); memcpy(avctx->extradata, sps_buf, extradata.SPSBufSize); if (need_pps) memcpy(avctx->extradata + extradata.SPSBufSize, pps_buf, extradata.PPSBufSize); avctx->extradata_size = extradata.SPSBufSize + need_pps * extradata.PPSBufSize; memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); return 0; } int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) { int ret; q->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; q->param.AsyncDepth = q->async_depth; q->async_fifo = av_fifo_alloc((1 + q->async_depth) * (sizeof(AVPacket) + sizeof(mfxSyncPoint) + sizeof(mfxBitstream*))); if (!q->async_fifo) return AVERROR(ENOMEM); if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->param.IOPattern = qsv->iopattern; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, q->load_plugins); if (ret < 0) return ret; q->session = q->internal_qs.session; } ret = init_video_param(avctx, q); if (ret < 0) return ret; ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error querying the encoding parameters\n"); return ff_qsv_error(ret); } ret = MFXVideoENCODE_Init(q->session, &q->param); if (MFX_WRN_PARTIAL_ACCELERATION==ret) { av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n"); } else if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing the encoder\n"); return ff_qsv_error(ret); } ret = qsv_retrieve_enc_params(avctx, q); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); return ret; } q->avctx = avctx; return 0; }
int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) { int opaque_alloc = 0; int ret; q->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; q->param.AsyncDepth = q->async_depth; q->async_fifo = av_fifo_alloc((1 + q->async_depth) * (sizeof(AVPacket) + sizeof(mfxSyncPoint) + sizeof(mfxBitstream*))); if (!q->async_fifo) return AVERROR(ENOMEM); if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->param.IOPattern = qsv->iopattern; opaque_alloc = qsv->opaque_alloc; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_session, q->load_plugins); if (ret < 0) return ret; q->session = q->internal_session; } ret = init_video_param(avctx, q); if (ret < 0) return ret; ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error querying the encoding parameters\n"); return ff_qsv_error(ret); } if (opaque_alloc) { ret = qsv_init_opaque_alloc(avctx, q); if (ret < 0) return ret; } if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; int i, j; q->extparam = av_mallocz_array(qsv->nb_ext_buffers + q->nb_extparam_internal, sizeof(*q->extparam)); if (!q->extparam) return AVERROR(ENOMEM); q->param.ExtParam = q->extparam; for (i = 0; i < qsv->nb_ext_buffers; i++) q->param.ExtParam[i] = qsv->ext_buffers[i]; q->param.NumExtParam = qsv->nb_ext_buffers; for (i = 0; i < q->nb_extparam_internal; i++) { for (j = 0; j < qsv->nb_ext_buffers; j++) { if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId) break; } if (j < qsv->nb_ext_buffers) continue; q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i]; } } else { q->param.ExtParam = q->extparam_internal; q->param.NumExtParam = q->nb_extparam_internal; } ret = MFXVideoENCODE_Init(q->session, &q->param); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing the encoder\n"); return ff_qsv_error(ret); } ret = qsv_retrieve_enc_params(avctx, q); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); return ret; } q->avctx = avctx; return 0; }
static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) { uint8_t sps_buf[128]; uint8_t pps_buf[128]; mfxExtCodingOptionSPSPPS extradata = { .Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS, .Header.BufferSz = sizeof(extradata), .SPSBuffer = sps_buf, .SPSBufSize = sizeof(sps_buf), .PPSBuffer = pps_buf, .PPSBufSize = sizeof(pps_buf) }; mfxExtBuffer *ext_buffers[] = { (mfxExtBuffer*)&extradata, }; int ret; q->param.ExtParam = ext_buffers; q->param.NumExtParam = FF_ARRAY_ELEMS(ext_buffers); ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); if (ret < 0) return ff_qsv_error(ret); q->packet_size = q->param.mfx.BufferSizeInKB * 1000; if (!extradata.SPSBufSize || !extradata.PPSBufSize) { av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx.\n"); return AVERROR_UNKNOWN; } avctx->extradata = av_malloc(extradata.SPSBufSize + extradata.PPSBufSize + FF_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) return AVERROR(ENOMEM); memcpy(avctx->extradata, sps_buf, extradata.SPSBufSize); memcpy(avctx->extradata + extradata.SPSBufSize, pps_buf, extradata.PPSBufSize); avctx->extradata_size = extradata.SPSBufSize + extradata.PPSBufSize; memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); return 0; } int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) { int ret; q->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; q->param.AsyncDepth = q->async_depth; if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->param.IOPattern = qsv->iopattern; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_session); if (ret < 0) return ret; q->session = q->internal_session; } ret = init_video_param(avctx, q); if (ret < 0) return ret; ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error querying the encoding parameters\n"); return ff_qsv_error(ret); } ret = MFXVideoENCODE_Init(q->session, &q->param); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing the encoder\n"); return ff_qsv_error(ret); } ret = qsv_retrieve_enc_params(avctx, q); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); return ret; } avctx->coded_frame = av_frame_alloc(); if (!avctx->coded_frame) return AVERROR(ENOMEM); q->avctx = avctx; return 0; }
int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt) { mfxVideoParam param = { { 0 } }; mfxBitstream bs = { { { 0 } } }; int ret; enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_QSV, AV_PIX_FMT_NV12, AV_PIX_FMT_NONE }; q->iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; if (!q->session) { if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->iopattern = qsv->iopattern; q->ext_buffers = qsv->ext_buffers; q->nb_ext_buffers = qsv->nb_ext_buffers; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, q->load_plugins); if (ret < 0) return ret; q->session = q->internal_qs.session; } } if (avpkt->size) { bs.Data = avpkt->data; bs.DataLength = avpkt->size; bs.MaxLength = bs.DataLength; bs.TimeStamp = avpkt->pts; } else return AVERROR_INVALIDDATA; ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Unsupported codec_id %08x\n", avctx->codec_id); return ret; } param.mfx.CodecId = ret; ret = MFXVideoDECODE_DecodeHeader(q->session, &bs, ¶m); if (MFX_ERR_MORE_DATA==ret) { /* this code means that header not found so we return packet size to skip a current packet */ return avpkt->size; } else if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Decode header error %d\n", ret); return ff_qsv_error(ret); } param.IOPattern = q->iopattern; param.AsyncDepth = q->async_depth; param.ExtParam = q->ext_buffers; param.NumExtParam = q->nb_ext_buffers; param.mfx.FrameInfo.BitDepthLuma = 8; param.mfx.FrameInfo.BitDepthChroma = 8; ret = MFXVideoDECODE_Init(q->session, ¶m); if (ret < 0) { if (MFX_ERR_INVALID_VIDEO_PARAM==ret) { av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder, unsupported video\n"); } else { av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder %d\n", ret); } return ff_qsv_error(ret); } ret = ff_get_format(avctx, pix_fmts); if (ret < 0) return ret; avctx->pix_fmt = ret; avctx->profile = param.mfx.CodecProfile; avctx->level = param.mfx.CodecLevel; avctx->coded_width = param.mfx.FrameInfo.Width; avctx->coded_height = param.mfx.FrameInfo.Height; avctx->width = param.mfx.FrameInfo.CropW - param.mfx.FrameInfo.CropX; avctx->height = param.mfx.FrameInfo.CropH - param.mfx.FrameInfo.CropY; /* maximum decoder latency should be not exceed max DPB size for h.264 and HEVC which is 16 for both cases. So weare pre-allocating fifo big enough for 17 elements: */ if (!q->async_fifo) { q->async_fifo = av_fifo_alloc((1 + 16) * (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); if (!q->async_fifo) return AVERROR(ENOMEM); } q->input_fifo = av_fifo_alloc(1024*16); if (!q->input_fifo) return AVERROR(ENOMEM); q->engine_ready = 1; return 0; }
int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt) { mfxVideoParam param = { { 0 } }; mfxBitstream bs = { { { 0 } } }; int ret; q->iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; if (!q->session) { if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; q->session = qsv->session; q->iopattern = qsv->iopattern; q->ext_buffers = qsv->ext_buffers; q->nb_ext_buffers = qsv->nb_ext_buffers; } if (!q->session) { ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL); if (ret < 0) return ret; q->session = q->internal_qs.session; } } if (avpkt->size) { bs.Data = avpkt->data; bs.DataLength = avpkt->size; bs.MaxLength = bs.DataLength; bs.TimeStamp = avpkt->pts; } else return AVERROR_INVALIDDATA; ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Unsupported codec_id %08x\n", avctx->codec_id); return ret; } param.mfx.CodecId = ret; ret = MFXVideoDECODE_DecodeHeader(q->session, &bs, ¶m); if (MFX_ERR_MORE_DATA==ret) { return AVERROR(EAGAIN); } else if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Decode header error %d\n", ret); return ff_qsv_error(ret); } param.IOPattern = q->iopattern; param.AsyncDepth = q->async_depth; param.ExtParam = q->ext_buffers; param.NumExtParam = q->nb_ext_buffers; param.mfx.FrameInfo.BitDepthLuma = 8; param.mfx.FrameInfo.BitDepthChroma = 8; ret = MFXVideoDECODE_Init(q->session, ¶m); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error initializing the MFX video decoder\n"); return ff_qsv_error(ret); } avctx->pix_fmt = AV_PIX_FMT_NV12; avctx->profile = param.mfx.CodecProfile; avctx->level = param.mfx.CodecLevel; avctx->coded_width = param.mfx.FrameInfo.Width; avctx->coded_height = param.mfx.FrameInfo.Height; avctx->width = param.mfx.FrameInfo.CropW - param.mfx.FrameInfo.CropX; avctx->height = param.mfx.FrameInfo.CropH - param.mfx.FrameInfo.CropY; q->async_fifo = av_fifo_alloc((1 + q->async_depth) * (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); if (!q->async_fifo) return AVERROR(ENOMEM); return 0; }