2 * Intel MediaSDK QSV based H.264 / HEVC decoder
4 * copyright (c) 2013 Luca Barbato
5 * copyright (c) 2015 Anton Khirnov
7 * This file is part of Libav.
9 * Libav is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * Libav is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with Libav; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <mfx/mfxvideo.h>
30 #include "libavutil/common.h"
31 #include "libavutil/fifo.h"
32 #include "libavutil/opt.h"
36 #include "qsv_internal.h"
45 typedef struct QSVH2645Context
{
51 // the filter for converting to Annex B
52 AVBitStreamFilterContext
*bsf
;
54 AVFifoBuffer
*packet_fifo
;
57 AVPacket pkt_filtered
;
58 uint8_t *filtered_data
;
61 static void qsv_clear_buffers(QSVH2645Context
*s
)
64 while (av_fifo_size(s
->packet_fifo
) >= sizeof(pkt
)) {
65 av_fifo_generic_read(s
->packet_fifo
, &pkt
, sizeof(pkt
), NULL
);
66 av_packet_unref(&pkt
);
69 if (s
->filtered_data
!= s
->input_ref
.data
)
70 av_freep(&s
->filtered_data
);
71 s
->filtered_data
= NULL
;
72 av_packet_unref(&s
->input_ref
);
75 static av_cold
int qsv_decode_close(AVCodecContext
*avctx
)
77 QSVH2645Context
*s
= avctx
->priv_data
;
79 ff_qsv_decode_close(&s
->qsv
);
83 av_fifo_free(s
->packet_fifo
);
85 av_bitstream_filter_close(s
->bsf
);
90 static av_cold
int qsv_decode_init(AVCodecContext
*avctx
)
92 QSVH2645Context
*s
= avctx
->priv_data
;
95 if (avctx
->codec_id
== AV_CODEC_ID_HEVC
&& s
->load_plugin
!= LOAD_PLUGIN_NONE
) {
96 static const char *uid_hevcenc_sw
= "15dd936825ad475ea34e35f3f54217a6";
98 if (s
->qsv
.load_plugins
[0]) {
99 av_log(avctx
, AV_LOG_WARNING
,
100 "load_plugins is not empty, but load_plugin is not set to 'none'."
101 "The load_plugin value will be ignored.\n");
103 av_freep(&s
->qsv
.load_plugins
);
104 s
->qsv
.load_plugins
= av_strdup(uid_hevcenc_sw
);
105 if (!s
->qsv
.load_plugins
)
106 return AVERROR(ENOMEM
);
110 s
->packet_fifo
= av_fifo_alloc(sizeof(AVPacket
));
111 if (!s
->packet_fifo
) {
112 ret
= AVERROR(ENOMEM
);
116 if (avctx
->codec_id
== AV_CODEC_ID_H264
)
117 s
->bsf
= av_bitstream_filter_init("h264_mp4toannexb");
119 s
->bsf
= av_bitstream_filter_init("hevc_mp4toannexb");
121 ret
= AVERROR(ENOMEM
);
125 s
->qsv
.iopattern
= MFX_IOPATTERN_OUT_SYSTEM_MEMORY
;
129 qsv_decode_close(avctx
);
133 static int qsv_decode_frame(AVCodecContext
*avctx
, void *data
,
134 int *got_frame
, AVPacket
*avpkt
)
136 QSVH2645Context
*s
= avctx
->priv_data
;
137 AVFrame
*frame
= data
;
140 /* buffer the input packet */
142 AVPacket input_ref
= { 0 };
144 if (av_fifo_space(s
->packet_fifo
) < sizeof(input_ref
)) {
145 ret
= av_fifo_realloc2(s
->packet_fifo
,
146 av_fifo_size(s
->packet_fifo
) + sizeof(input_ref
));
151 ret
= av_packet_ref(&input_ref
, avpkt
);
154 av_fifo_generic_write(s
->packet_fifo
, &input_ref
, sizeof(input_ref
), NULL
);
157 /* process buffered data */
158 while (!*got_frame
) {
159 /* prepare the input data -- convert to Annex B if needed */
160 if (s
->pkt_filtered
.size
<= 0) {
164 if (av_fifo_size(s
->packet_fifo
) < sizeof(AVPacket
))
165 return avpkt
->size ? avpkt
->size
: ff_qsv_process_data(avctx
, &s
->qsv
, frame
, got_frame
, avpkt
);
167 if (s
->filtered_data
!= s
->input_ref
.data
)
168 av_freep(&s
->filtered_data
);
169 s
->filtered_data
= NULL
;
170 av_packet_unref(&s
->input_ref
);
172 av_fifo_generic_read(s
->packet_fifo
, &s
->input_ref
, sizeof(s
->input_ref
), NULL
);
173 ret
= av_bitstream_filter_filter(s
->bsf
, avctx
, NULL
,
174 &s
->filtered_data
, &size
,
175 s
->input_ref
.data
, s
->input_ref
.size
, 0);
177 s
->filtered_data
= s
->input_ref
.data
;
178 size
= s
->input_ref
.size
;
180 s
->pkt_filtered
= s
->input_ref
;
181 s
->pkt_filtered
.data
= s
->filtered_data
;
182 s
->pkt_filtered
.size
= size
;
185 ret
= ff_qsv_process_data(avctx
, &s
->qsv
, frame
, got_frame
, &s
->pkt_filtered
);
189 s
->pkt_filtered
.size
-= ret
;
190 s
->pkt_filtered
.data
+= ret
;
196 static void qsv_decode_flush(AVCodecContext
*avctx
)
198 QSVH2645Context
*s
= avctx
->priv_data
;
200 qsv_clear_buffers(s
);
201 ff_qsv_decode_flush(avctx
, &s
->qsv
);
204 #define OFFSET(x) offsetof(QSVH2645Context, x)
205 #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
207 #if CONFIG_HEVC_QSV_DECODER
208 AVHWAccel ff_hevc_qsv_hwaccel
= {
210 .type
= AVMEDIA_TYPE_VIDEO
,
211 .id
= AV_CODEC_ID_HEVC
,
212 .pix_fmt
= AV_PIX_FMT_QSV
,
215 static const AVOption hevc_options
[] = {
216 { "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
},
218 { "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" },
219 { "none", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= LOAD_PLUGIN_NONE
}, 0, 0, VD
, "load_plugin" },
220 { "hevc_sw", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= LOAD_PLUGIN_HEVC_SW
}, 0, 0, VD
, "load_plugin" },
222 { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session",
223 OFFSET(qsv
.load_plugins
), AV_OPT_TYPE_STRING
, { .str
= "" }, 0, 0, VD
},
227 static const AVClass hevc_class
= {
228 .class_name
= "hevc_qsv",
229 .item_name
= av_default_item_name
,
230 .option
= hevc_options
,
231 .version
= LIBAVUTIL_VERSION_INT
,
234 AVCodec ff_hevc_qsv_decoder
= {
236 .long_name
= NULL_IF_CONFIG_SMALL("HEVC (Intel Quick Sync Video acceleration)"),
237 .priv_data_size
= sizeof(QSVH2645Context
),
238 .type
= AVMEDIA_TYPE_VIDEO
,
239 .id
= AV_CODEC_ID_HEVC
,
240 .init
= qsv_decode_init
,
241 .decode
= qsv_decode_frame
,
242 .flush
= qsv_decode_flush
,
243 .close
= qsv_decode_close
,
244 .capabilities
= CODEC_CAP_DELAY
| CODEC_CAP_DR1
,
245 .priv_class
= &hevc_class
,
246 .pix_fmts
= (const enum AVPixelFormat
[]){ AV_PIX_FMT_NV12
,
252 #if CONFIG_H264_QSV_DECODER
253 AVHWAccel ff_h264_qsv_hwaccel
= {
255 .type
= AVMEDIA_TYPE_VIDEO
,
256 .id
= AV_CODEC_ID_H264
,
257 .pix_fmt
= AV_PIX_FMT_QSV
,
260 static const AVOption options
[] = {
261 { "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
},
265 static const AVClass
class = {
266 .class_name
= "h264_qsv",
267 .item_name
= av_default_item_name
,
269 .version
= LIBAVUTIL_VERSION_INT
,
272 AVCodec ff_h264_qsv_decoder
= {
274 .long_name
= NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"),
275 .priv_data_size
= sizeof(QSVH2645Context
),
276 .type
= AVMEDIA_TYPE_VIDEO
,
277 .id
= AV_CODEC_ID_H264
,
278 .init
= qsv_decode_init
,
279 .decode
= qsv_decode_frame
,
280 .flush
= qsv_decode_flush
,
281 .close
= qsv_decode_close
,
282 .capabilities
= AV_CODEC_CAP_DELAY
| AV_CODEC_CAP_DR1
,
283 .priv_class
= &class,
284 .pix_fmts
= (const enum AVPixelFormat
[]){ AV_PIX_FMT_NV12
,