[FFmpeg-cvslog] libavcodec/mjpeg_qsv: Add QSV MJPEG encoder
Huang, Zhengxu
git at videolan.org
Wed Nov 8 18:48:52 EET 2017
ffmpeg | branch: master | Huang, Zhengxu <zhengxu.maxwell at gmail.com> | Fri Jul 21 12:12:44 2017 +0800| [2fd6e7d077f590e4d7195356f9baeb271f8b9ae2] | committer: Maxym Dmytrychenko
libavcodec/mjpeg_qsv: Add QSV MJPEG encoder
usage:
-hwaccel qsv -c:v h264_qsv -i in -c:v mjpeg_qsv -global_quality 80 -f
mjpeg out
Signed-off-by: ChaoX A Liu <chaox.a.liu at gmail.com>
Signed-off-by: Zhengxu Huang <zhengxu.maxwell at gmail.com>
Signed-off-by: Andrew Zhang <huazh407 at gmail.com
Signed-off-by: Maxym Dmytrychenko <maxim.d33 at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=2fd6e7d077f590e4d7195356f9baeb271f8b9ae2
---
Changelog | 1 +
configure | 2 +
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/qsv.c | 3 ++
libavcodec/qsvenc.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-
libavcodec/qsvenc_jpeg.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 192 insertions(+), 2 deletions(-)
diff --git a/Changelog b/Changelog
index adcca3fcc5..82e3e3a0ef 100644
--- a/Changelog
+++ b/Changelog
@@ -17,6 +17,7 @@ version <next>:
- ClearVideo decoder (I-frames only)
- support for decoding through D3D11VA in avconv
- Cinepak encoder
+- Intel QSV-accelerated MJPEG encoding
version 12:
diff --git a/configure b/configure
index d92ce33e6d..35ae03182a 100755
--- a/configure
+++ b/configure
@@ -2279,6 +2279,8 @@ hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser hevc_qsv_hwaccel qsvde
hevc_qsv_encoder_select="hevc_ps qsvenc"
hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC"
hevc_vaapi_encoder_select="vaapi_encode golomb"
+mjpeg_qsv_encoder_deps="libmfx"
+mjpeg_qsv_encoder_select="qsvenc"
mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG"
mjpeg_vaapi_encoder_select="vaapi_encode jpegtables"
mpeg2_mmal_decoder_deps="mmal"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 2b9158822d..12bf8fecb7 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -319,6 +319,7 @@ OBJS-$(CONFIG_MIMIC_DECODER) += mimic.o
OBJS-$(CONFIG_MJPEG_DECODER) += mjpegdec.o
OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpegenc_common.o
OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o
+OBJS-$(CONFIG_MJPEG_QSV_ENCODER) += qsvenc_jpeg.o
OBJS-$(CONFIG_MJPEG_VAAPI_ENCODER) += vaapi_encode_mjpeg.o
OBJS-$(CONFIG_MLP_DECODER) += mlpdec.o mlpdsp.o
OBJS-$(CONFIG_MMVIDEO_DECODER) += mmvideo.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 5635ae150c..3fcea5be0d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -509,6 +509,7 @@ void avcodec_register_all(void)
REGISTER_ENCODER(HEVC_NVENC, hevc_nvenc);
REGISTER_ENCODER(HEVC_QSV, hevc_qsv);
REGISTER_ENCODER(HEVC_VAAPI, hevc_vaapi);
+ REGISTER_ENCODER(MJPEG_QSV, mjpeg_qsv);
REGISTER_ENCODER(MJPEG_VAAPI, mjpeg_vaapi);
REGISTER_ENCODER(MPEG2_QSV, mpeg2_qsv);
REGISTER_ENCODER(MPEG2_VAAPI, mpeg2_vaapi);
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 30d612f0e1..a8ae65622c 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -20,6 +20,7 @@
#include <mfx/mfxvideo.h>
#include <mfx/mfxplugin.h>
+#include <mfx/mfxjpeg.h>
#include <stdio.h>
#include <string.h>
@@ -56,6 +57,8 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
case AV_CODEC_ID_VP8:
return MFX_CODEC_VP8;
#endif
+ case AV_CODEC_ID_MJPEG:
+ return MFX_CODEC_JPEG;
default:
break;
}
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 7c6ad09dda..c7e5947361 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -353,6 +353,64 @@ static int rc_supported(QSVEncContext *q)
return 1;
}
+static int init_video_param_jpeg(AVCodecContext *avctx, QSVEncContext *q)
+{
+ enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ?
+ avctx->sw_pix_fmt : avctx->pix_fmt;
+ const AVPixFmtDescriptor *desc;
+ int ret;
+
+ ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
+ if (ret < 0)
+ return AVERROR_BUG;
+ q->param.mfx.CodecId = ret;
+
+ if (avctx->level > 0)
+ q->param.mfx.CodecLevel = avctx->level;
+ q->param.mfx.CodecProfile = q->profile;
+
+ desc = av_pix_fmt_desc_get(sw_format);
+ if (!desc)
+ return AVERROR_BUG;
+
+ ff_qsv_map_pixfmt(sw_format, &q->param.mfx.FrameInfo.FourCC);
+
+ 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 = desc->comp[0].depth;
+ q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth;
+ q->param.mfx.FrameInfo.Shift = desc->comp[0].depth > 8;
+
+ q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, 16);
+ q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, 16);
+
+ if (avctx->hw_frames_ctx) {
+ AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
+ AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
+ q->param.mfx.FrameInfo.Width = frames_hwctx->surfaces[0].Info.Width;
+ q->param.mfx.FrameInfo.Height = frames_hwctx->surfaces[0].Info.Height;
+ }
+
+ if (avctx->framerate.den > 0 && avctx->framerate.num > 0) {
+ q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num;
+ q->param.mfx.FrameInfo.FrameRateExtD = avctx->framerate.den;
+ } else {
+ q->param.mfx.FrameInfo.FrameRateExtN = avctx->time_base.den;
+ q->param.mfx.FrameInfo.FrameRateExtD = avctx->time_base.num;
+ }
+
+ q->param.mfx.Interleaved = 1;
+ q->param.mfx.Quality = av_clip(avctx->global_quality, 1, 100);
+ q->param.mfx.RestartInterval = 0;
+
+ return 0;
+}
+
static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
{
enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ?
@@ -568,6 +626,24 @@ FF_ENABLE_DEPRECATION_WARNINGS
return 0;
}
+static int qsv_retrieve_enc_jpeg_params(AVCodecContext *avctx, QSVEncContext *q)
+{
+ int ret = 0;
+
+ ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param);
+ if (ret < 0)
+ return ff_qsv_print_error(avctx, ret,
+ "Error calling GetVideoParam");
+
+ q->packet_size = q->param.mfx.BufferSizeInKB * 1000;
+
+ // for qsv mjpeg the return value maybe 0 so alloc the buffer
+ if (q->packet_size == 0)
+ q->packet_size = q->param.mfx.FrameInfo.Height * q->param.mfx.FrameInfo.Width * 4;
+
+ return 0;
+}
+
static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q)
{
AVCPBProperties *cpb_props;
@@ -770,7 +846,15 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
if (ret < 0)
return ret;
- ret = init_video_param(avctx, q);
+ // in the mfxInfoMFX struct, JPEG is different from other codecs
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_MJPEG:
+ ret = init_video_param_jpeg(avctx, q);
+ break;
+ default:
+ ret = init_video_param(avctx, q);
+ break;
+ }
if (ret < 0)
return ret;
@@ -830,7 +914,14 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
ff_qsv_print_warning(avctx, ret,
"Warning in encoder initialization");
- ret = qsv_retrieve_enc_params(avctx, q);
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_MJPEG:
+ ret = qsv_retrieve_enc_jpeg_params(avctx, q);
+ break;
+ default:
+ ret = qsv_retrieve_enc_params(avctx, q);
+ break;
+ }
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n");
return ret;
diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c
new file mode 100644
index 0000000000..3fa17f13ab
--- /dev/null
+++ b/libavcodec/qsvenc_jpeg.c
@@ -0,0 +1,91 @@
+/*
+ * Intel MediaSDK QSV based MJPEG encoder
+ *
+ * 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 "internal.h"
+#include "h264.h"
+#include "qsv.h"
+#include "qsv_internal.h"
+#include "qsvenc.h"
+
+typedef struct QSVMJPEGEncContext {
+ AVClass *class;
+ QSVEncContext qsv;
+} QSVMJPEGEncContext;
+
+static av_cold int qsv_enc_init(AVCodecContext *avctx)
+{
+ QSVMJPEGEncContext *q = avctx->priv_data;
+
+ return ff_qsv_enc_init(avctx, &q->qsv);
+}
+
+static int qsv_enc_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ QSVMJPEGEncContext *q = avctx->priv_data;
+
+ return ff_qsv_encode(avctx, &q->qsv, pkt, frame, got_packet);
+}
+
+static av_cold int qsv_enc_close(AVCodecContext *avctx)
+{
+ QSVMJPEGEncContext *q = avctx->priv_data;
+
+ return ff_qsv_enc_close(avctx, &q->qsv);
+}
+
+#define OFFSET(x) offsetof(QSVMJPEGEncContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { NULL },
+};
+
+static const AVClass class = {
+ .class_name = "mjpeg_qsv encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mjpeg_qsv_encoder = {
+ .name = "mjpeg_qsv",
+ .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Intel Quick Sync Video acceleration)"),
+ .priv_data_size = sizeof(QSVMJPEGEncContext),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MJPEG,
+ .init = qsv_enc_init,
+ .encode2 = qsv_enc_frame,
+ .close = qsv_enc_close,
+ .capabilities = AV_CODEC_CAP_DELAY,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_QSV,
+ AV_PIX_FMT_NONE },
+ .priv_class = &class,
+};
More information about the ffmpeg-cvslog
mailing list