On 2015-07-04 02:33, Tim W. wrote:
On Tue, Jun 30, 2015 at 8:24 PM, Anton Khirnov <an...@khirnov.net> wrote:

---
 configure                 |   1 +
 libavcodec/Makefile       |   1 +
 libavcodec/allcodecs.c    |   1 +
 libavcodec/hevc.h         |   3 +
 libavcodec/qsv.c          |  14 +++
 libavcodec/qsv_internal.h |   4 +
 libavcodec/qsvenc.c       |  22 +++--
 libavcodec/qsvenc_hevc.c  | 236
++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 273 insertions(+), 9 deletions(-)
 create mode 100644 libavcodec/qsvenc_hevc.c

diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
index 8b06e1f..60377c2 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -113,5 +117,15 @@ int ff_qsv_init_internal_session(AVCodecContext
*avctx, mfxSession *session)
            "Initialized an internal MFX session using %s
implementation\n",
            desc);

+#if QSV_VERSION_ATLEAST(1, 8)


This will ensure MFXVideoUSER_Load is available, but MFX_PLUGINID_HEVCE_SW
was introduced in the dispatcher with MFX_VERSION_MINOR == 10; if you
really want to support building with older dispatchers/headers, you can
always hardcode it:

{{0x2f, 0xca, 0x99, 0x74, 0x9f, 0xdb, 0x49, 0xae, 0xb1, 0x21, 0xa5, 0xb6,
0x3e, 0xf5, 0x68, 0xf7}}


+    if (avctx->codec_id == AV_CODEC_ID_HEVC) {

+        ret = MFXVideoUSER_Load(*session, &MFX_PLUGINID_HEVCE_SW, 1);


MFX_PLUGINID_HEVCE_SW is the plugin UID for the software-based HEVC
encoder. Loading it in a hardware-accelerated session appears to work (all
the way to MFXVideoENCODE_Init), so at least we're good there.

That being said, if the session is hardware-accelerated, we could/should try loading MFX_PLUGINID_HEVCE_HW first? You'll need the latest dispatcher
to build it (MFX_VERSION_MINOR == 15), but you can also hardcode it:

{{0x6f, 0xad, 0xc7, 0x91, 0xa0, 0xc2, 0xeb, 0x47, 0x9a, 0xb6, 0xdc, 0xd5,
0xea, 0x9d, 0xa3, 0x47}}

There is no way to test it directly, but if you ask nicely Maxym
(Dmytrychenko) may be able to do it for you.


The thing is, the HW plugin I have hangs for me (on Linux). Does it work for you in Handbrake?


+        if (ret < 0) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "Could not load the HEVC encoding plugin, encoding
will likely fail\n");


Have you seen a case where the plugin didn't load but encoding worked? Else
we may as well fail here.


As Luca said, there can be a theoretical future version that incorporates HEVC encoding into the core. And failing here does not really give us any benefits
that I can see.


diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index d13848a..4b6d9c4 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -30,6 +30,10 @@

 #define ASYNC_DEPTH_DEFAULT 4       // internal parallelism

+#define QSV_VERSION_ATLEAST(MAJOR, MINOR)   \
+    (MFX_VERSION_MAJOR > (MAJOR) ||         \
+     MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR))
+


This would be more useful if MFX_VERSION_* wasn't hardcoded, that way we could check the API version exposed by the runtime (via MFXQueryVersion) if
the need were to arise in the future.


diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 690d5aa..a724611 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -124,15 +124,19 @@ static int init_video_param(AVCodecContext *avctx,
QSVEncContext *q)
         break;
     }


FrameInfo.Width should be 32-aligned for (QSV-based) HEVC encoding,
according to Maxym. Makes sense, too.



Ok, first time I hear about it, but will fix.


-    q->extco.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION;
-    q->extco.Header.BufferSz      = sizeof(q->extco);
-    q->extco.CAVLC                = avctx->coder_type ==
FF_CODER_TYPE_VLC ?
-                                    MFX_CODINGOPTION_ON :
MFX_CODINGOPTION_UNKNOWN;
-
-    q->extparam[0] = (mfxExtBuffer *)&q->extco;
-
-    q->param.ExtParam    = q->extparam;
-    q->param.NumExtParam = FF_ARRAY_ELEMS(q->extparam);
+    // the HEVC encoder plugin currently fails if coding options
+    // are provided
+    if (avctx->codec_id != AV_CODEC_ID_HEVC) {
+        q->extco.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION;
+        q->extco.Header.BufferSz      = sizeof(q->extco);
+        q->extco.CAVLC                = avctx->coder_type ==
FF_CODER_TYPE_VLC ?
+                                        MFX_CODINGOPTION_ON :
MFX_CODINGOPTION_UNKNOWN;
+
+        q->extparam[0] = (mfxExtBuffer *)&q->extco;
+
+        q->param.ExtParam    = q->extparam;
+        q->param.NumExtParam = FF_ARRAY_ELEMS(q->extparam);
+    }


I guess this is OK for now, but using MFXVideoENCODE_Query would be better.
Probably outside the scope of this patch though.


diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c
new file mode 100644
index 0000000..9934472
--- /dev/null
+++ b/libavcodec/qsvenc_hevc.c
@@ -0,0 +1,236 @@
+/*
+ * Intel MediaSDK QSV based H.264 enccoder
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <mfx/mfxvideo.h>
+
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "get_bits.h"
+#include "hevc.h"
+#include "internal.h"
+#include "qsv.h"
+#include "qsv_internal.h"
+#include "qsvenc.h"
+
+typedef struct QSVHEVCEncContext {
+    AVClass *class;
+    QSVEncContext qsv;
+} QSVHEVCEncContext;
+
+static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)


So here we go. Some HEVC encoder plugin implementations (Intel Media Server
Studio Professional Edition 2015 R3, trial version) will not return any
SPS/PPS at all for HEVC.

I lost the download but I believe this issue goes back to the original
"HEVC encode plug-in" for Media SDK 2014, I already had the issue with
HandBrake back then.

What happens is MFXVideoENCODE_GetVideoParam, but the buffers are not
touched, and the buffer sizes are also untouched (so SPSBufSize ==
sizeof(sps_buf), and so forth).

generate_fake_vps ends up erroring out at "Unexpected NAL type in the
extradata".

You could decide to just not support such implementations. But an easy
workaround (IMO) is to simply initialize the encode session, encode a dummy
blank frame, flush the encoder if required, and extract all 3 parameter
sets (SPS, PPS and VPS) from the bitstream (with the added benefit that the
extracted VPS is not fake).

Then you simply close and re-open the encoding session.

Note: I haven't tested this in a scenario where the same MFX session
already has QSV decoding initialized, it might be safer to use a dedicated session for this. But using the same mfxVideoParam to configure the dummy
and the real encodes works fine, in my experience.


As discussed on IRC.
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to