#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
#include "libavutil/time.h"
+#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "internal.h"
+#include "decode.h"
#include "qsv.h"
#include "qsv_internal.h"
#include "qsvdec.h"
NULL
};
+static int ff_qsv_get_continuous_buffer(AVCodecContext *avctx, AVFrame *frame, AVBufferPool *pool)
+{
+ int ret = 0;
+
+ ff_decode_frame_props(avctx, frame);
+
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_NV12:
+ frame->linesize[0] = FFALIGN(avctx->width, 128);
+ break;
+ case AV_PIX_FMT_P010:
+ frame->linesize[0] = 2 * FFALIGN(avctx->width, 128);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ frame->linesize[1] = frame->linesize[0];
+ frame->buf[0] = av_buffer_pool_get(pool);
+ if (!frame->buf[0])
+ return AVERROR(ENOMEM);
+
+ frame->data[0] = frame->buf[0]->data;
+ frame->data[1] = frame->data[0] +
+ frame->linesize[0] * FFALIGN(avctx->height, 64);
+
+ ret = ff_attach_decode_data(frame);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref)
{
int ret;
+ if (q->gpu_copy == MFX_GPUCOPY_ON &&
+ !(q->iopattern & MFX_IOPATTERN_OUT_SYSTEM_MEMORY))
+ av_log(avctx, AV_LOG_WARNING, "GPU-accelerated memory copy "
+ "only works in MFX_IOPATTERN_OUT_SYSTEM_MEMORY.\n");
if (session) {
q->session = session;
} else if (hw_frames_ref) {
- if (q->internal_session) {
- MFXClose(q->internal_session);
- q->internal_session = NULL;
+ if (q->internal_qs.session) {
+ MFXClose(q->internal_qs.session);
+ q->internal_qs.session = NULL;
}
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
if (!q->frames_ctx.hw_frames_ctx)
return AVERROR(ENOMEM);
- ret = ff_qsv_init_session_frames(avctx, &q->internal_session,
+ ret = ff_qsv_init_session_frames(avctx, &q->internal_qs.session,
&q->frames_ctx, q->load_plugins,
- q->iopattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY);
+ q->iopattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY,
+ q->gpu_copy);
if (ret < 0) {
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
return ret;
}
- q->session = q->internal_session;
+ q->session = q->internal_qs.session;
} else if (hw_device_ref) {
- if (q->internal_session) {
- MFXClose(q->internal_session);
- q->internal_session = NULL;
+ if (q->internal_qs.session) {
+ MFXClose(q->internal_qs.session);
+ q->internal_qs.session = NULL;
}
- ret = ff_qsv_init_session_device(avctx, &q->internal_session,
- hw_device_ref, q->load_plugins);
+ ret = ff_qsv_init_session_device(avctx, &q->internal_qs.session,
+ hw_device_ref, q->load_plugins, q->gpu_copy);
if (ret < 0)
return ret;
- q->session = q->internal_session;
+ q->session = q->internal_qs.session;
} else {
- if (!q->internal_session) {
- ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
- q->load_plugins);
+ if (!q->internal_qs.session) {
+ ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
+ q->load_plugins, q->gpu_copy);
if (ret < 0)
return ret;
}
- q->session = q->internal_session;
+ q->session = q->internal_qs.session;
}
/* make sure the decoder is uninitialized */
iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
q->iopattern = iopattern;
+ ff_qsv_print_iopattern(avctx, q->iopattern, "Decoder");
+
ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx, avctx->hw_device_ctx);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
q->frame_info = param->mfx.FrameInfo;
+ if (!avctx->hw_frames_ctx)
+ q->pool = av_buffer_pool_init(av_image_get_buffer_size(avctx->pix_fmt,
+ FFALIGN(avctx->width, 128), FFALIGN(avctx->height, 64), 1), av_buffer_allocz);
return 0;
}
{
int ret;
- ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
+ if (q->pool)
+ ret = ff_qsv_get_continuous_buffer(avctx, frame->frame, q->pool);
+ else
+ ret = ff_get_buffer(avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
+
if (ret < 0)
return ret;
av_fifo_free(q->async_fifo);
q->async_fifo = NULL;
- av_parser_close(q->parser);
- avcodec_free_context(&q->avctx_internal);
-
- if (q->internal_session)
- MFXClose(q->internal_session);
+ ff_qsv_close_internal_session(&q->internal_qs);
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
av_buffer_unref(&q->frames_ctx.mids_buf);
+ av_buffer_pool_uninit(&q->pool);
return 0;
}
int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q,
AVFrame *frame, int *got_frame, AVPacket *pkt)
{
- uint8_t *dummy_data;
- int dummy_size;
int ret;
mfxVideoParam param = { 0 };
enum AVPixelFormat pix_fmt = AV_PIX_FMT_NV12;
- if (!q->avctx_internal) {
- q->avctx_internal = avcodec_alloc_context3(NULL);
- if (!q->avctx_internal)
- return AVERROR(ENOMEM);
-
- q->avctx_internal->codec_id = avctx->codec_id;
-
- q->parser = av_parser_init(avctx->codec_id);
- if (!q->parser)
- return AVERROR(ENOMEM);
-
- q->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
- }
-
if (!pkt->size)
return qsv_decode(avctx, q, frame, got_frame, pkt);
- /* we assume the packets are already split properly and want
- * just the codec parameters here */
- av_parser_parse2(q->parser, q->avctx_internal,
- &dummy_data, &dummy_size,
- pkt->data, pkt->size, pkt->pts, pkt->dts,
- pkt->pos);
-
/* TODO: flush delayed frames on reinit */
// sw_pix_fmt, coded_width/height should be set for ff_get_format(),
return qsv_decode(avctx, q, frame, got_frame, pkt);
reinit_fail:
- q->orig_pix_fmt = q->parser->format = avctx->pix_fmt = AV_PIX_FMT_NONE;
+ q->orig_pix_fmt = avctx->pix_fmt = AV_PIX_FMT_NONE;
return ret;
}