2 * Intel MediaSDK QSV based HEVC encoder
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <sys/types.h>
25 #include <mfx/mfxvideo.h>
27 #include "libavutil/common.h"
28 #include "libavutil/opt.h"
31 #include "bytestream.h"
35 #include "h2645_parse.h"
38 #include "qsv_internal.h"
47 typedef struct QSVHEVCEncContext
{
53 static int generate_fake_vps(QSVEncContext
*q
, AVCodecContext
*avctx
)
59 H2645NAL sps_nal
= { NULL
};
62 uint8_t vps_buf
[128], vps_rbsp_buf
[128];
63 uint8_t *new_extradata
;
65 int ret
, i
, type
, vps_size
;
67 if (!avctx
->extradata_size
) {
68 av_log(avctx
, AV_LOG_ERROR
, "No extradata returned from libmfx\n");
69 return AVERROR_UNKNOWN
;
73 ret
= ff_h2645_extract_rbsp(avctx
->extradata
+ 4, avctx
->extradata_size
- 4, &sps_nal
);
75 av_log(avctx
, AV_LOG_ERROR
, "Error unescaping the SPS buffer\n");
79 ret
= init_get_bits8(&gb
, sps_nal
.data
, sps_nal
.size
);
81 av_freep(&sps_nal
.rbsp_buffer
);
86 type
= get_bits(&gb
, 6);
87 if (type
!= HEVC_NAL_SPS
) {
88 av_log(avctx
, AV_LOG_ERROR
, "Unexpected NAL type in the extradata: %d\n",
90 av_freep(&sps_nal
.rbsp_buffer
);
91 return AVERROR_INVALIDDATA
;
95 ret
= ff_hevc_parse_sps(&sps
, &gb
, &sps_id
, 0, NULL
, avctx
);
96 av_freep(&sps_nal
.rbsp_buffer
);
98 av_log(avctx
, AV_LOG_ERROR
, "Error parsing the SPS\n");
102 /* generate the VPS */
103 vps
.vps_max_layers
= 1;
104 vps
.vps_max_sub_layers
= sps
.max_sub_layers
;
105 memcpy(&vps
.ptl
, &sps
.ptl
, sizeof(vps
.ptl
));
106 vps
.vps_sub_layer_ordering_info_present_flag
= 1;
107 for (i
= 0; i
< HEVC_MAX_SUB_LAYERS
; i
++) {
108 vps
.vps_max_dec_pic_buffering
[i
] = sps
.temporal_layer
[i
].max_dec_pic_buffering
;
109 vps
.vps_num_reorder_pics
[i
] = sps
.temporal_layer
[i
].num_reorder_pics
;
110 vps
.vps_max_latency_increase
[i
] = sps
.temporal_layer
[i
].max_latency_increase
;
113 vps
.vps_num_layer_sets
= 1;
114 vps
.vps_timing_info_present_flag
= sps
.vui
.vui_timing_info_present_flag
;
115 vps
.vps_num_units_in_tick
= sps
.vui
.vui_num_units_in_tick
;
116 vps
.vps_time_scale
= sps
.vui
.vui_time_scale
;
117 vps
.vps_poc_proportional_to_timing_flag
= sps
.vui
.vui_poc_proportional_to_timing_flag
;
118 vps
.vps_num_ticks_poc_diff_one
= sps
.vui
.vui_num_ticks_poc_diff_one_minus1
+ 1;
120 /* generate the encoded RBSP form of the VPS */
121 ret
= ff_hevc_encode_nal_vps(&vps
, sps
.vps_id
, vps_rbsp_buf
, sizeof(vps_rbsp_buf
));
123 av_log(avctx
, AV_LOG_ERROR
, "Error writing the VPS\n");
127 /* escape and add the startcode */
128 bytestream2_init(&gbc
, vps_rbsp_buf
, ret
);
129 bytestream2_init_writer(&pbc
, vps_buf
, sizeof(vps_buf
));
131 bytestream2_put_be32(&pbc
, 1); // startcode
132 bytestream2_put_byte(&pbc
, HEVC_NAL_VPS
<< 1); // NAL
133 bytestream2_put_byte(&pbc
, 1); // header
135 while (bytestream2_get_bytes_left(&gbc
)) {
136 uint32_t b
= bytestream2_peek_be24(&gbc
);
138 bytestream2_put_be24(&pbc
, 3);
139 bytestream2_skip(&gbc
, 2);
141 bytestream2_put_byte(&pbc
, bytestream2_get_byte(&gbc
));
144 vps_size
= bytestream2_tell_p(&pbc
);
145 new_extradata
= av_mallocz(vps_size
+ avctx
->extradata_size
+ AV_INPUT_BUFFER_PADDING_SIZE
);
147 return AVERROR(ENOMEM
);
148 memcpy(new_extradata
, vps_buf
, vps_size
);
149 memcpy(new_extradata
+ vps_size
, avctx
->extradata
, avctx
->extradata_size
);
151 av_freep(&avctx
->extradata
);
152 avctx
->extradata
= new_extradata
;
153 avctx
->extradata_size
+= vps_size
;
158 static av_cold
int qsv_enc_init(AVCodecContext
*avctx
)
160 QSVHEVCEncContext
*q
= avctx
->priv_data
;
163 if (q
->load_plugin
!= LOAD_PLUGIN_NONE
) {
164 static const char * const uid_hevcenc_sw
= "2fca99749fdb49aeb121a5b63ef568f7";
165 static const char * const uid_hevcenc_hw
= "6fadc791a0c2eb479ab6dcd5ea9da347";
167 if (q
->qsv
.load_plugins
[0]) {
168 av_log(avctx
, AV_LOG_WARNING
,
169 "load_plugins is not empty, but load_plugin is not set to 'none'."
170 "The load_plugin value will be ignored.\n");
172 av_freep(&q
->qsv
.load_plugins
);
174 if (q
->load_plugin
== LOAD_PLUGIN_HEVC_SW
)
175 q
->qsv
.load_plugins
= av_strdup(uid_hevcenc_sw
);
177 q
->qsv
.load_plugins
= av_strdup(uid_hevcenc_hw
);
179 if (!q
->qsv
.load_plugins
)
180 return AVERROR(ENOMEM
);
184 // HEVC and H264 meaning of the value is shifted by 1, make it consistent
185 q
->qsv
.idr_interval
++;
187 ret
= ff_qsv_enc_init(avctx
, &q
->qsv
);
191 ret
= generate_fake_vps(&q
->qsv
, avctx
);
193 ff_qsv_enc_close(avctx
, &q
->qsv
);
200 static int qsv_enc_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
201 const AVFrame
*frame
, int *got_packet
)
203 QSVHEVCEncContext
*q
= avctx
->priv_data
;
205 return ff_qsv_encode(avctx
, &q
->qsv
, pkt
, frame
, got_packet
);
208 static av_cold
int qsv_enc_close(AVCodecContext
*avctx
)
210 QSVHEVCEncContext
*q
= avctx
->priv_data
;
212 return ff_qsv_enc_close(avctx
, &q
->qsv
);
216 #define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW
218 #define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW
221 #define OFFSET(x) offsetof(QSVHEVCEncContext, x)
222 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
223 static const AVOption options
[] = {
226 { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv
.idr_interval
), AV_OPT_TYPE_INT
, { .i64
= 0 }, -1, INT_MAX
, VE
, "idr_interval" },
227 { "begin_only", "Output an IDR-frame only at the beginning of the stream", 0, AV_OPT_TYPE_CONST
, { .i64
= -1 }, 0, 0, VE
, "idr_interval" },
228 { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin
), AV_OPT_TYPE_INT
, { .i64
= LOAD_PLUGIN_DEFAULT
}, LOAD_PLUGIN_NONE
, LOAD_PLUGIN_HEVC_HW
, VE
, "load_plugin" },
229 { "none", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= LOAD_PLUGIN_NONE
}, 0, 0, VE
, "load_plugin" },
230 { "hevc_sw", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= LOAD_PLUGIN_HEVC_SW
}, 0, 0, VE
, "load_plugin" },
231 { "hevc_hw", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= LOAD_PLUGIN_HEVC_HW
}, 0, 0, VE
, "load_plugin" },
233 { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session",
234 OFFSET(qsv
.load_plugins
), AV_OPT_TYPE_STRING
, { .str
= "" }, 0, 0, VE
},
236 { "profile", NULL
, OFFSET(qsv
.profile
), AV_OPT_TYPE_INT
, { .i64
= MFX_PROFILE_UNKNOWN
}, 0, INT_MAX
, VE
, "profile" },
237 { "unknown", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= MFX_PROFILE_UNKNOWN
}, INT_MIN
, INT_MAX
, VE
, "profile" },
238 { "main", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= MFX_PROFILE_HEVC_MAIN
}, INT_MIN
, INT_MAX
, VE
, "profile" },
239 { "main10", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= MFX_PROFILE_HEVC_MAIN10
}, INT_MIN
, INT_MAX
, VE
, "profile" },
240 { "mainsp", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= MFX_PROFILE_HEVC_MAINSP
}, INT_MIN
, INT_MAX
, VE
, "profile" },
242 { "low_power", "enable low power mode (experimental, many limitations by mfx version, HW platform, BRC modes, etc.", OFFSET(qsv
.low_power
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, VE
},
248 static const AVClass
class = {
249 .class_name
= "hevc_qsv encoder",
250 .item_name
= av_default_item_name
,
252 .version
= LIBAVUTIL_VERSION_INT
,
255 static const AVCodecDefault qsv_enc_defaults
[] = {
258 // same as the x264 default
262 { "flags", "+cgop" },
263 #if FF_API_PRIVATE_OPT
264 { "b_strategy", "-1" },
269 AVCodec ff_hevc_qsv_encoder
= {
271 .long_name
= NULL_IF_CONFIG_SMALL("HEVC (Intel Quick Sync Video acceleration)"),
272 .priv_data_size
= sizeof(QSVHEVCEncContext
),
273 .type
= AVMEDIA_TYPE_VIDEO
,
274 .id
= AV_CODEC_ID_HEVC
,
275 .init
= qsv_enc_init
,
276 .encode2
= qsv_enc_frame
,
277 .close
= qsv_enc_close
,
278 .capabilities
= AV_CODEC_CAP_DELAY
| AV_CODEC_CAP_HYBRID
,
279 .pix_fmts
= (const enum AVPixelFormat
[]){ AV_PIX_FMT_NV12
,
283 .priv_class
= &class,
284 .defaults
= qsv_enc_defaults
,
285 .caps_internal
= FF_CODEC_CAP_INIT_CLEANUP
,
286 .wrapper_name
= "qsv",