@@ -3035,6 +3035,8 @@ oss_indev_deps_any="soundcard_h sys_soundcard_h"
oss_outdev_deps_any="soundcard_h sys_soundcard_h"
pulse_indev_deps="libpulse"
pulse_outdev_deps="libpulse"
+screen_qsv_indev_deps="libmfx"
+screen_qsv_indev_select="screen_qsv_decoder"
qtkit_indev_extralibs="-framework QTKit -framework Foundation -framework QuartzCore"
qtkit_indev_select="qtkit"
sdl2_outdev_deps="sdl2"
@@ -38,6 +38,7 @@ OBJS-$(CONFIG_PULSE_INDEV) += pulse_audio_dec.o \
pulse_audio_common.o timefilter.o
OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \
pulse_audio_common.o
+OBJS-$(CONFIG_SCREEN_QSV_INDEV) += qsvscreen.o
OBJS-$(CONFIG_QTKIT_INDEV) += qtkit.o
OBJS-$(CONFIG_SDL2_OUTDEV) += sdl2.o
OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o
@@ -57,6 +57,7 @@ static void register_all(void)
REGISTER_OUTDEV (OPENGL, opengl);
REGISTER_INOUTDEV(OSS, oss);
REGISTER_INOUTDEV(PULSE, pulse);
+ REGISTER_INDEV (SCREEN_QSV, screen_qsv);
REGISTER_INDEV (QTKIT, qtkit);
REGISTER_OUTDEV (SDL2, sdl2);
REGISTER_INOUTDEV(SNDIO, sndio);
new file mode 100644
@@ -0,0 +1,216 @@
+/*
+ * Intel QSV screen capture interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2017 Alexander Bilyak <bilyak.alexander@gmail.com>
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Intel QSV Screen capture demuxer interface
+ * @author Alexander Bilyak <bilyak.alexander@gmail.com>
+ * @note As Intel Media SDK provide screen capture as plug-in to QSV decoder
+ * so this "device" is nothing more than wrapper around QSV decoder
+ * with appropiate settings.
+ */
+
+#include "config.h"
+#include "libavformat/internal.h"
+#include "libavutil/opt.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/time.h"
+#include "libavutil/imgutils.h"
+
+/**
+ * QSV screen capture context
+ */
+typedef struct QSVScreenContext {
+
+ const AVClass *class; /**< Class for private options */
+
+ AVCodecContext *avctx; /**< Codec context used for fake decoding */
+ AVCodec *codec; /**< Codec used for fake decoding */
+
+ int draw_mouse; /**< Draw mouse cursor (private option) */
+ int width; /**< Width of the grab frame (private option) */
+ int height; /**< Height of the grab frame (private option) */
+} QSVScreenContext;
+
+/**
+ * Initializes the QSV screen device demuxer (public device demuxer API).
+ *
+ * @param avctx Context from avformat core
+ *
+ * @return 0 on success, a negative AVERROR on error
+ */
+static int screen_qsv_read_header(AVFormatContext *avctx)
+{
+ int ret;
+ AVStream *st;
+ QSVScreenContext *ctx = avctx->priv_data;
+ AVDictionary* opts = NULL;
+
+ ctx->codec = avcodec_find_decoder_by_name("screen_qsv");
+ if (!ctx->codec) {
+ ret = AVERROR_DECODER_NOT_FOUND;
+ goto error;
+ }
+
+ ctx->avctx = avcodec_alloc_context3(ctx->codec);
+ if (!ctx->avctx) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ ctx->avctx->width = ctx->width;
+ ctx->avctx->height = ctx->height;
+
+ av_dict_set_int(&opts, "draw_mouse", ctx->draw_mouse, 0 );
+
+ ret = avcodec_open2(ctx->avctx, ctx->codec, &opts);
+ if (ret)
+ goto error;
+
+ st = avformat_new_stream(avctx, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ avpriv_set_pts_info(st, 96, 1, 1000000); /* 96 bits pts in microseconds */
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codecpar->codec_tag = MKTAG('N', 'V', '1', '2');
+ st->codecpar->width = ctx->width;
+ st->codecpar->height = ctx->height;
+ st->codecpar->format = AV_PIX_FMT_NV12;
+ st->codecpar->bit_rate = st->codecpar->width * st->codecpar->height * 12;
+
+ ret = avcodec_send_packet(ctx->avctx, NULL);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ if (ctx->avctx)
+ avcodec_free_context(&ctx->avctx);
+
+ return ret;
+}
+
+/**
+ * Grabs a frame from QSV screen device (public device demuxer API).
+ *
+ * @param avctx Context from avformat core
+ *
+ * @param pkt Packet holding the grabbed frame
+ *
+ * @return frame size in bytes, a negative AVERROR on error.
+ */
+static int screen_qsv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ QSVScreenContext *ctx = avctx->priv_data;
+ int ret;
+
+ int size = ctx->width * ctx->height * 12/8;
+
+ AVFrame *frame = av_frame_alloc();
+ if (!frame)
+ return AVERROR(ENOMEM);
+
+ frame->format = AV_PIX_FMT_NV12;
+ frame->width = ctx->width;
+ frame->height = ctx->height;
+
+ ret = av_frame_get_buffer(frame, 32);
+ if (ret < 0)
+ goto error;
+
+ ret = avcodec_receive_frame(ctx->avctx, frame);
+ if (ret < 0)
+ goto error;
+
+ ret = av_new_packet(pkt, size);
+ if (ret < 0)
+ goto error;
+
+ ret = av_image_copy_to_buffer(pkt->data, size, (const uint8_t **)frame->data,
+ frame->linesize, frame->format, frame->width, frame->height, 1);
+ if (ret < 0)
+ goto error;
+
+ pkt->stream_index = 0;
+ pkt->pts = av_gettime();
+ pkt->pos = frame->pkt_pos;
+ pkt->size = size;
+
+ av_frame_free(&frame);
+
+ return size;
+error:
+ if (frame) {
+ av_frame_free(&frame);
+ }
+
+ return ret;
+}
+
+/**
+ * Closes QSV screen device frame grabber (public device demuxer API).
+ *
+ * @param avctx Context from avformat core
+ *
+ * @return 0 on success, a negative AVERROR on error
+ */
+static int screen_qsv_read_close(AVFormatContext *avctx)
+{
+ QSVScreenContext *ctx = avctx->priv_data;
+
+ if (ctx->avctx)
+ avcodec_free_context(&ctx->avctx);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(struct QSVScreenContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass screen_qsv_class = {
+ .class_name = "QSVScreen indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+/** QSV Screen frame grabber device demuxer declaration */
+AVInputFormat ff_screen_qsv_demuxer = {
+ .name = "screen_qsv",
+ .long_name = NULL_IF_CONFIG_SMALL("Intel QSV screen capture"),
+ .priv_data_size = sizeof(QSVScreenContext),
+ .read_header = screen_qsv_read_header,
+ .read_packet = screen_qsv_read_packet,
+ .read_close = screen_qsv_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &screen_qsv_class,
+};