Commit 1f26a231 authored by Mark Thompson's avatar Mark Thompson

qsv: Merge libav implementation

Merged as-at libav 398f015f, and therefore includes outstanding
skipped merges 04b17ff9 and 130e1f1d.

All features not in libav are preserved, and no options change.
parent 309fe16a
This diff is collapsed.
......@@ -21,21 +21,6 @@
#ifndef AVCODEC_QSV_INTERNAL_H
#define AVCODEC_QSV_INTERNAL_H
#if CONFIG_VAAPI
#define AVCODEC_QSV_LINUX_SESSION_HANDLE
#endif //CONFIG_VAAPI
#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <va/va.h>
#include <va/va_drm.h>
#endif
#include <mfx/mfxvideo.h>
#include "libavutil/frame.h"
......@@ -43,7 +28,7 @@
#include "avcodec.h"
#define QSV_VERSION_MAJOR 1
#define QSV_VERSION_MINOR 9
#define QSV_VERSION_MINOR 1
#define ASYNC_DEPTH_DEFAULT 4 // internal parallelism
......@@ -65,23 +50,26 @@ typedef struct QSVFrame {
struct QSVFrame *next;
} QSVFrame;
typedef struct QSVSession {
mfxSession session;
#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
int fd_display;
VADisplay va_display;
#endif
} QSVSession;
typedef struct QSVFramesContext {
AVBufferRef *hw_frames_ctx;
mfxFrameInfo info;
mfxMemId *mids;
int nb_mids;
} QSVFramesContext;
/**
* Convert a libmfx error code into a ffmpeg error code.
* Convert a libmfx error code into an ffmpeg error code.
*/
int ff_qsv_error(int mfx_err);
int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id);
int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile);
int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
const char *load_plugins);
int ff_qsv_close_internal_session(QSVSession *qs);
int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *session,
QSVFramesContext *qsv_frames_ctx,
const char *load_plugins, int opaque);
#endif /* AVCODEC_QSV_INTERNAL_H */
This diff is collapsed.
......@@ -41,7 +41,9 @@ typedef struct QSVContext {
// the session we allocated internally, in case the caller did not provide
// one
QSVSession internal_qs;
mfxSession internal_session;
QSVFramesContext frames_ctx;
/**
* a linked list of frames currently being used by QSV
......@@ -49,22 +51,11 @@ typedef struct QSVContext {
QSVFrame *work_frames;
AVFifoBuffer *async_fifo;
AVFifoBuffer *input_fifo;
// we should to buffer input packets at some cases
// else it is not possible to handle dynamic stream changes correctly
// this fifo uses for input packets buffering
AVFifoBuffer *pkt_fifo;
// this flag indicates that header parsed,
// decoder instance created and ready to general decoding
int engine_ready;
// we can not just re-init decoder if different sequence header arrived
// we should to deliver all buffered frames but we can not decode new packets
// this time. So when reinit_pending is non-zero we flushing decoder and
// accumulate new arrived packets into pkt_fifo
int reinit_pending;
// the internal parser and codec context for parsing the data
AVCodecParserContext *parser;
AVCodecContext *avctx_internal;
enum AVPixelFormat orig_pix_fmt;
// options set by the caller
int async_depth;
......@@ -78,11 +69,10 @@ typedef struct QSVContext {
int ff_qsv_map_pixfmt(enum AVPixelFormat format);
int ff_qsv_decode(AVCodecContext *s, QSVContext *q,
AVFrame *frame, int *got_frame,
AVPacket *avpkt);
int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q,
AVFrame *frame, int *got_frame, AVPacket *pkt);
void ff_qsv_decode_reset(AVCodecContext *avctx, QSVContext *q);
void ff_qsv_decode_flush(AVCodecContext *avctx, QSVContext *q);
int ff_qsv_decode_close(QSVContext *q);
......
......@@ -33,11 +33,14 @@
#include "avcodec.h"
#include "internal.h"
#include "qsv_internal.h"
#include "qsvdec.h"
#include "qsv.h"
enum LoadPlugin {
LOAD_PLUGIN_NONE,
LOAD_PLUGIN_HEVC_SW,
LOAD_PLUGIN_HEVC_HW,
};
typedef struct QSVH2645Context {
......@@ -86,7 +89,8 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx)
int ret;
if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != LOAD_PLUGIN_NONE) {
static const char *uid_hevcenc_sw = "15dd936825ad475ea34e35f3f54217a6";
static const char *uid_hevcdec_sw = "15dd936825ad475ea34e35f3f54217a6";
static const char *uid_hevcdec_hw = "33a61c0b4c27454ca8d85dde757c6f8e";
if (s->qsv.load_plugins[0]) {
av_log(avctx, AV_LOG_WARNING,
......@@ -94,22 +98,22 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx)
"The load_plugin value will be ignored.\n");
} else {
av_freep(&s->qsv.load_plugins);
s->qsv.load_plugins = av_strdup(uid_hevcenc_sw);
if (s->load_plugin == LOAD_PLUGIN_HEVC_SW)
s->qsv.load_plugins = av_strdup(uid_hevcdec_sw);
else
s->qsv.load_plugins = av_strdup(uid_hevcdec_hw);
if (!s->qsv.load_plugins)
return AVERROR(ENOMEM);
}
}
s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
if (!s->packet_fifo) {
ret = AVERROR(ENOMEM);
goto fail;
}
if (avctx->codec_id == AV_CODEC_ID_H264) {
//regarding ticks_per_frame description, should be 2 for h.264:
avctx->ticks_per_frame = 2;
}
return 0;
fail:
qsv_decode_close(avctx);
......@@ -184,7 +188,7 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data,
/* no more data */
if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
return avpkt->size ? avpkt->size : ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt);
av_packet_unref(&s->pkt_filtered);
......@@ -202,7 +206,7 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data,
av_packet_unref(&input_ref);
}
ret = ff_qsv_decode(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered);
ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered);
if (ret < 0)
return ret;
......@@ -216,7 +220,9 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data,
static void qsv_decode_flush(AVCodecContext *avctx)
{
QSVH2645Context *s = avctx->priv_data;
ff_qsv_decode_reset(avctx, &s->qsv);
qsv_clear_buffers(s);
ff_qsv_decode_flush(avctx, &s->qsv);
}
#define OFFSET(x) offsetof(QSVH2645Context, x)
......@@ -233,9 +239,10 @@ AVHWAccel ff_hevc_qsv_hwaccel = {
static const AVOption hevc_options[] = {
{ "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD },
{ "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_SW, VD, "load_plugin" },
{ "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" },
{ "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" },
{ "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" },
{ "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" },
{ "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session",
OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
......
/*
* Intel MediaSDK QSV based MPEG-2 video decoder
* Intel MediaSDK QSV based MPEG-2 decoder
*
* copyright (c) 2015 Anton Khirnov
*
* This file is part of FFmpeg.
*
......@@ -18,32 +20,70 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <string.h>
#include <mfx/mfxvideo.h>
#include "libavutil/common.h"
#include "libavutil/fifo.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "qsv_internal.h"
#include "qsvdec.h"
#include "qsv.h"
typedef struct QSVMPEG2Context {
AVClass *class;
QSVContext qsv;
AVFifoBuffer *packet_fifo;
AVPacket input_ref;
} QSVMPEG2Context;
static void qsv_clear_buffers(QSVMPEG2Context *s)
{
AVPacket pkt;
while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
av_packet_unref(&pkt);
}
av_packet_unref(&s->input_ref);
}
static av_cold int qsv_decode_close(AVCodecContext *avctx)
{
QSVMPEG2Context *s = avctx->priv_data;
ff_qsv_decode_close(&s->qsv);
qsv_clear_buffers(s);
av_fifo_free(s->packet_fifo);
return 0;
}
static av_cold int qsv_decode_init(AVCodecContext *avctx)
{
QSVMPEG2Context *s = avctx->priv_data;
int ret;
s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
if (!s->packet_fifo) {
ret = AVERROR(ENOMEM);
goto fail;
}
return 0;
fail:
qsv_decode_close(avctx);
return ret;
}
static int qsv_decode_frame(AVCodecContext *avctx, void *data,
......@@ -51,14 +91,53 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data,
{
QSVMPEG2Context *s = avctx->priv_data;
AVFrame *frame = data;
int ret;
/* buffer the input packet */
if (avpkt->size) {
AVPacket input_ref = { 0 };
if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
ret = av_fifo_realloc2(s->packet_fifo,
av_fifo_size(s->packet_fifo) + sizeof(input_ref));
if (ret < 0)
return ret;
}
ret = av_packet_ref(&input_ref, avpkt);
if (ret < 0)
return ret;
av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
}
return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
/* process buffered data */
while (!*got_frame) {
if (s->input_ref.size <= 0) {
/* no more data */
if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt);
av_packet_unref(&s->input_ref);
av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL);
}
ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->input_ref);
if (ret < 0)
return ret;
s->input_ref.size -= ret;
s->input_ref.data += ret;
}
return avpkt->size;
}
static void qsv_decode_flush(AVCodecContext *avctx)
{
QSVMPEG2Context *s = avctx->priv_data;
ff_qsv_decode_reset(avctx, &s->qsv);
qsv_clear_buffers(s);
ff_qsv_decode_flush(avctx, &s->qsv);
}
AVHWAccel ff_mpeg2_qsv_hwaccel = {
......
......@@ -21,18 +21,37 @@
#include <stdint.h>
#include <string.h>
#include <mfx/mfxvideo.h>
#include "libavutil/common.h"
#include "libavutil/fifo.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "qsv_internal.h"
#include "qsvdec.h"
#include "qsv.h"
typedef struct QSVVC1Context {
AVClass *class;
QSVContext qsv;
AVFifoBuffer *packet_fifo;
AVPacket input_ref;
} QSVVC1Context;
static void qsv_clear_buffers(QSVVC1Context *s)
{
AVPacket pkt;
while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) {
av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL);
av_packet_unref(&pkt);
}
av_packet_unref(&s->input_ref);
}
static av_cold int qsv_decode_close(AVCodecContext *avctx)
{
......@@ -40,22 +59,82 @@ static av_cold int qsv_decode_close(AVCodecContext *avctx)
ff_qsv_decode_close(&s->qsv);
qsv_clear_buffers(s);
av_fifo_free(s->packet_fifo);
return 0;
}
static av_cold int qsv_decode_init(AVCodecContext *avctx)
{
QSVVC1Context *s = avctx->priv_data;
int ret;
s->packet_fifo = av_fifo_alloc(sizeof(AVPacket));
if (!s->packet_fifo) {
ret = AVERROR(ENOMEM);
goto fail;
}
return 0;
fail:
qsv_decode_close(avctx);
return ret;
}
static int qsv_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
QSVVC1Context *s = avctx->priv_data;
AVFrame *frame = data;
AVFrame *frame = data;
int ret;
/* buffer the input packet */
if (avpkt->size) {
AVPacket input_ref = { 0 };
if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
ret = av_fifo_realloc2(s->packet_fifo,
av_fifo_size(s->packet_fifo) + sizeof(input_ref));
if (ret < 0)
return ret;
}
ret = av_packet_ref(&input_ref, avpkt);
if (ret < 0)
return ret;
av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL);
}
return ff_qsv_decode(avctx, &s->qsv, frame, got_frame, avpkt);
/* process buffered data */
while (!*got_frame) {
if (s->input_ref.size <= 0) {
/* no more data */
if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt);
av_packet_unref(&s->input_ref);
av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL);
}
ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->input_ref);
if (ret < 0)
return ret;
s->input_ref.size -= ret;
s->input_ref.data += ret;
}
return avpkt->size;
}
static void qsv_decode_flush(AVCodecContext *avctx)
{
QSVVC1Context *s = avctx->priv_data;
ff_qsv_decode_reset(avctx, &s->qsv);
qsv_clear_buffers(s);
ff_qsv_decode_flush(avctx, &s->qsv);
}
AVHWAccel ff_vc1_qsv_hwaccel = {
......@@ -85,11 +164,11 @@ AVCodec ff_vc1_qsv_decoder = {
.priv_data_size = sizeof(QSVVC1Context),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_VC1,
.init = NULL,
.init = qsv_decode_init,
.decode = qsv_decode_frame,
.flush = qsv_decode_flush,
.close = qsv_decode_close,
.capabilities = AV_CODEC_CAP_DELAY,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1,
.priv_class = &class,
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
AV_PIX_FMT_QSV,
......
......@@ -26,6 +26,8 @@
#include <mfx/mfxvideo.h>
#include "libavutil/common.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_qsv.h"
#include "libavutil/mem.h"
#include "libavutil/log.h"
#include "libavutil/time.h"
......@@ -379,31 +381,25 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
q->param.mfx.EncodedOrder = 0;
q->param.mfx.BufferSizeInKB = 0;
q->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
q->param.mfx.FrameInfo.CropX = 0;
q->param.mfx.FrameInfo.CropY = 0;
q->param.mfx.FrameInfo.CropW = avctx->width;
q->param.mfx.FrameInfo.CropH = avctx->height;
q->param.mfx.FrameInfo.AspectRatioW = avctx->sample_aspect_ratio.num;
q->param.mfx.FrameInfo.AspectRatioH = avctx->sample_aspect_ratio.den;
q->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
q->param.mfx.FrameInfo.BitDepthLuma = 8;
q->param.mfx.FrameInfo.BitDepthChroma = 8;
q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, q->width_align);
if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
/* A true field layout (TFF or BFF) is not important here,
it will specified later during frame encoding. But it is important
to specify is frame progressive or not because allowed heigh alignment
does depend by this.
*/
q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
q->height_align = 32;
if (avctx->hw_frames_ctx) {
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
q->param.mfx.FrameInfo = frames_hwctx->surfaces[0].Info;
} else {
q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
q->height_align = 16;
q->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, q->width_align);
q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, 32);
q->param.mfx.FrameInfo.CropX = 0;
q->param.mfx.FrameInfo.CropY = 0;
q->param.mfx.FrameInfo.CropW = avctx->width;
q->param.mfx.FrameInfo.CropH = avctx->height;
q->param.mfx.FrameInfo.AspectRatioW = avctx->sample_aspect_ratio.num;
q->param.mfx.FrameInfo.AspectRatioH = avctx->sample_aspect_ratio.den;
q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
q->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
q->param.mfx.FrameInfo.BitDepthLuma = 8;
q->param.mfx.FrameInfo.BitDepthChroma = 8;
}
q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, q->height_align);
if (avctx->framerate.den > 0 && avctx->framerate.num > 0) {
q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num;
......@@ -536,7 +532,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2;
#if QSV_VERSION_ATLEAST(1,8)
#if QSV_HAVE_LA_DS
q->extco2.LookAheadDS = q->look_ahead_downsampling;
#endif
}
......@@ -673,12 +669,45 @@ static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q)
return 0;
}
static int qsvenc_init_session(AVCodecContext *avctx, QSVEncContext *q)
{
int ret;
if (avctx->hwaccel_context) {
AVQSVContext *qsv = avctx->hwaccel_context;
q->session = qsv->session;
} else if (avctx->hw_frames_ctx) {
q->frames_ctx.hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx);
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->param.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY);
if (ret < 0) {
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
return ret;
}
q->session = q->internal_session;
} else {
ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
q->load_plugins);
if (ret < 0)
return ret;
q->session = q->internal_session;
}
return 0;
}
int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
{
int iopattern = 0;
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) *
......@@ -689,32 +718,34 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
if (avctx->hwaccel_context) {
AVQSVContext *qsv = avctx->hwaccel_context;
q->session = qsv->session;
q->param.IOPattern = qsv->iopattern;
iopattern = qsv->iopattern;
opaque_alloc = qsv->opaque_alloc;
}
if (!q->session) {
ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
q->load_plugins);
if (ret < 0)
return ret;
if (avctx->hw_frames_ctx) {
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
q->session = q->internal_qs.session;
if (!iopattern) {
if (frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME)
iopattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY;
else if (frames_hwctx->frame_type &
(MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
iopattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
}
}
ret = init_video_param(avctx, q);
if (!iopattern)
iopattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
q->param.IOPattern = iopattern;
ret = qsvenc_init_session(avctx, q);
if (ret < 0)
return ret;
ret = MFXVideoENCODE_Query(q->session, &q->param,&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 %d querying encoder params\n", ret);
return ff_qsv_error(ret);
}
ret = init_video_param(avctx, q);
if (ret < 0)
return ret;
ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req);
if (ret < 0) {
......@@ -758,7 +789,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
}
ret = MFXVideoENCODE_Init(q->session, &q->param);
if (MFX_WRN_PARTIAL_ACCELERATION==ret) {
if (ret == MFX_WRN_PARTIAL_ACCELERATION) {
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");
......@@ -856,9 +887,8 @@ static int submit_frame(QSVEncContext *q, const AVFrame *frame,
qf->surface = (mfxFrameSurface1*)qf->frame->data[3];
} else {
/* make a copy if the input is not padded as libmfx requires */
if ( frame->height & (q->height_align - 1) ||
frame->linesize[0] & (q->width_align - 1)) {
qf->frame->height = FFALIGN(frame->height, q->height_align);
if (frame->height & 31 || frame->linesize[0] & (q->width_align - 1)) {
qf->frame->height = FFALIGN(frame->height, 32);
qf->frame->width = FFALIGN(frame->width, q->width_align);
ret = ff_get_buffer(q->avctx, qf->frame, AV_GET_BUFFER_FLAG_REF);
......@@ -924,7 +954,7 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
mfxBitstream *bs;
mfxFrameSurface1 *surf = NULL;
mfxSyncPoint *sync = NULL;
mfxSyncPoint *sync = NULL;
QSVFrame *qsv_frame = NULL;
mfxEncodeCtrl* enc_ctrl = NULL;
int ret;
......@@ -968,30 +998,21 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
do {
ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
if (ret == MFX_WRN_DEVICE_BUSY) {
if (ret == MFX_WRN_DEVICE_BUSY)
av_usleep(500);
continue;
}
break;
} while ( 1 );
} while (ret > 0);
if (ret < 0) {
av_packet_unref(&new_pkt);
av_freep(&bs);
if (ret == MFX_ERR_MORE_DATA)
return 0;
av_log(avctx, AV_LOG_ERROR, "EncodeFrameAsync returned %d\n", ret);
return ff_qsv_error(ret);
av_freep(&sync);
return (ret == MFX_ERR_MORE_DATA) ? 0 : ff_qsv_error(ret);
}
if (ret == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM) {
if (frame->interlaced_frame)
print_interlace_msg(avctx, q);
else
av_log(avctx, AV_LOG_WARNING,
"EncodeFrameAsync returned 'incompatible param' code\n");
}
if (sync) {
if (ret == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM && frame->interlaced_frame)
print_interlace_msg(avctx, q);
if (*sync) {
av_fifo_generic_write(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL);
av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL);
av_fifo_generic_write(q->async_fifo, &bs, sizeof(bs), NULL);
......@@ -1079,9 +1100,14 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
if (q->session)
MFXVideoENCODE_Close(q->session);
q->session = NULL;
ff_qsv_close_internal_session(&q->internal_qs);
if (q->internal_session)
MFXClose(q->internal_session);
q->session = NULL;
q->internal_session = NULL;
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
av_freep(&q->frames_ctx.mids);
q->frames_ctx.nb_mids = 0;
cur = q->work_frames;
while (cur) {
......
......@@ -42,6 +42,7 @@
#define QSV_HAVE_BREF_TYPE QSV_VERSION_ATLEAST(1, 8)
#define QSV_HAVE_LA QSV_VERSION_ATLEAST(1, 7)
#define QSV_HAVE_LA_DS QSV_VERSION_ATLEAST(1, 8)
#define QSV_HAVE_LA_HRD QSV_VERSION_ATLEAST(1, 11)
#define QSV_HAVE_ICQ QSV_VERSION_ATLEAST(1, 8)
#define QSV_HAVE_VCM QSV_VERSION_ATLEAST(1, 8)
......@@ -79,11 +80,10 @@ typedef struct QSVEncContext {
QSVFrame *work_frames;
mfxSession session;
QSVSession internal_qs;
mfxSession internal_session;
int packet_size;
int width_align;
int height_align;
mfxVideoParam param;
mfxFrameAllocRequest req;
......@@ -104,6 +104,8 @@ typedef struct QSVEncContext {
AVFifoBuffer *async_fifo;
QSVFramesContext frames_ctx;
// options set by the caller
int async_depth;
int idr_interval;
......
......@@ -111,8 +111,7 @@ static const AVOption options[] = {
{ "look_ahead", "Use VBR algorithm with look ahead", OFFSET(qsv.look_ahead), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
{ "look_ahead_depth", "Depth of look ahead in number frames", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE },
#endif
#if QSV_VERSION_ATLEAST(1,8)
#if QSV_HAVE_LA_DS
{ "look_ahead_downsampling", NULL, OFFSET(qsv.look_ahead_downsampling), AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" },
{ "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" },
{ "off" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment