Commit | Line | Data |
---|---|---|
72b7441a AK |
1 | /* |
2 | * Intel MediaSDK QSV encoder utility functions | |
3 | * | |
4 | * copyright (c) 2013 Yukinori Yamazoe | |
5 | * copyright (c) 2015 Anton Khirnov | |
6 | * | |
7 | * This file is part of Libav. | |
8 | * | |
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. | |
13 | * | |
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. | |
18 | * | |
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 | |
22 | */ | |
23 | ||
24 | #include <string.h> | |
25 | #include <sys/types.h> | |
26 | #include <mfx/mfxvideo.h> | |
27 | ||
28 | #include "libavutil/common.h" | |
29 | #include "libavutil/mem.h" | |
30 | #include "libavutil/log.h" | |
31 | #include "libavutil/time.h" | |
32 | #include "libavutil/imgutils.h" | |
33 | ||
34 | #include "avcodec.h" | |
35 | #include "internal.h" | |
36 | #include "qsv.h" | |
37 | #include "qsv_internal.h" | |
38 | #include "qsvenc.h" | |
39 | ||
4d8f536b AK |
40 | static const struct { |
41 | mfxU16 profile; | |
42 | const char *name; | |
43 | } profile_names[] = { | |
44 | { MFX_PROFILE_AVC_BASELINE, "baseline" }, | |
45 | { MFX_PROFILE_AVC_MAIN, "main" }, | |
46 | { MFX_PROFILE_AVC_EXTENDED, "extended" }, | |
47 | { MFX_PROFILE_AVC_HIGH, "high" }, | |
48 | #if QSV_VERSION_ATLEAST(1, 15) | |
49 | { MFX_PROFILE_AVC_HIGH_422, "high 422" }, | |
50 | #endif | |
51 | #if QSV_VERSION_ATLEAST(1, 4) | |
52 | { MFX_PROFILE_AVC_CONSTRAINED_BASELINE, "constrained baseline" }, | |
53 | { MFX_PROFILE_AVC_CONSTRAINED_HIGH, "constrained high" }, | |
54 | { MFX_PROFILE_AVC_PROGRESSIVE_HIGH, "progressive high" }, | |
55 | #endif | |
56 | { MFX_PROFILE_MPEG2_SIMPLE, "simple" }, | |
57 | { MFX_PROFILE_MPEG2_MAIN, "main" }, | |
58 | { MFX_PROFILE_MPEG2_HIGH, "high" }, | |
59 | { MFX_PROFILE_VC1_SIMPLE, "simple" }, | |
60 | { MFX_PROFILE_VC1_MAIN, "main" }, | |
61 | { MFX_PROFILE_VC1_ADVANCED, "advanced" }, | |
62 | #if QSV_VERSION_ATLEAST(1, 8) | |
63 | { MFX_PROFILE_HEVC_MAIN, "main" }, | |
64 | { MFX_PROFILE_HEVC_MAIN10, "main10" }, | |
65 | { MFX_PROFILE_HEVC_MAINSP, "mainsp" }, | |
66 | #endif | |
67 | }; | |
68 | ||
69 | static const char *print_profile(mfxU16 profile) | |
70 | { | |
71 | int i; | |
72 | for (i = 0; i < FF_ARRAY_ELEMS(profile_names); i++) | |
73 | if (profile == profile_names[i].profile) | |
74 | return profile_names[i].name; | |
75 | return "unknown"; | |
76 | } | |
77 | ||
78 | static const struct { | |
79 | mfxU16 rc_mode; | |
80 | const char *name; | |
81 | } rc_names[] = { | |
82 | { MFX_RATECONTROL_CBR, "CBR" }, | |
83 | { MFX_RATECONTROL_VBR, "VBR" }, | |
84 | { MFX_RATECONTROL_CQP, "CQP" }, | |
85 | { MFX_RATECONTROL_AVBR, "AVBR" }, | |
86 | #if QSV_HAVE_LA | |
87 | { MFX_RATECONTROL_LA, "LA" }, | |
88 | #endif | |
89 | #if QSV_HAVE_ICQ | |
90 | { MFX_RATECONTROL_ICQ, "ICQ" }, | |
91 | { MFX_RATECONTROL_LA_ICQ, "LA_ICQ" }, | |
92 | #endif | |
93 | #if QSV_HAVE_VCM | |
94 | { MFX_RATECONTROL_VCM, "VCM" }, | |
95 | #endif | |
96 | #if QSV_VERSION_ATLEAST(1, 10) | |
97 | { MFX_RATECONTROL_LA_EXT, "LA_EXT" }, | |
98 | #endif | |
99 | #if QSV_HAVE_LA_HRD | |
100 | { MFX_RATECONTROL_LA_HRD, "LA_HRD" }, | |
101 | #endif | |
102 | #if QSV_HAVE_QVBR | |
103 | { MFX_RATECONTROL_QVBR, "QVBR" }, | |
104 | #endif | |
105 | }; | |
106 | ||
107 | static const char *print_ratecontrol(mfxU16 rc_mode) | |
108 | { | |
109 | int i; | |
110 | for (i = 0; i < FF_ARRAY_ELEMS(rc_names); i++) | |
111 | if (rc_mode == rc_names[i].rc_mode) | |
112 | return rc_names[i].name; | |
113 | return "unknown"; | |
114 | } | |
115 | ||
116 | static const char *print_threestate(mfxU16 val) | |
117 | { | |
118 | if (val == MFX_CODINGOPTION_ON) | |
119 | return "ON"; | |
120 | else if (val == MFX_CODINGOPTION_OFF) | |
121 | return "OFF"; | |
122 | return "unknown"; | |
123 | } | |
124 | ||
125 | static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, | |
126 | mfxExtBuffer **coding_opts) | |
127 | { | |
128 | mfxInfoMFX *info = &q->param.mfx; | |
129 | ||
130 | mfxExtCodingOption *co = (mfxExtCodingOption*)coding_opts[0]; | |
131 | #if QSV_HAVE_CO2 | |
132 | mfxExtCodingOption2 *co2 = (mfxExtCodingOption2*)coding_opts[1]; | |
133 | #endif | |
134 | #if QSV_HAVE_CO3 | |
135 | mfxExtCodingOption3 *co3 = (mfxExtCodingOption3*)coding_opts[2]; | |
136 | #endif | |
137 | ||
138 | av_log(avctx, AV_LOG_VERBOSE, "profile: %s; level: %"PRIu16"\n", | |
139 | print_profile(info->CodecProfile), info->CodecLevel); | |
140 | ||
141 | av_log(avctx, AV_LOG_VERBOSE, "GopPicSize: %"PRIu16"; GopRefDist: %"PRIu16"; GopOptFlag: ", | |
142 | info->GopPicSize, info->GopRefDist); | |
143 | if (info->GopOptFlag & MFX_GOP_CLOSED) | |
144 | av_log(avctx, AV_LOG_VERBOSE, "closed "); | |
145 | if (info->GopOptFlag & MFX_GOP_STRICT) | |
146 | av_log(avctx, AV_LOG_VERBOSE, "strict "); | |
147 | av_log(avctx, AV_LOG_VERBOSE, "; IdrInterval: %"PRIu16"\n", info->IdrInterval); | |
148 | ||
149 | av_log(avctx, AV_LOG_VERBOSE, "TargetUsage: %"PRIu16"; RateControlMethod: %s\n", | |
150 | info->TargetUsage, print_ratecontrol(info->RateControlMethod)); | |
151 | ||
152 | if (info->RateControlMethod == MFX_RATECONTROL_CBR || | |
153 | info->RateControlMethod == MFX_RATECONTROL_VBR | |
154 | #if QSV_HAVE_VCM | |
155 | || info->RateControlMethod == MFX_RATECONTROL_VCM | |
156 | #endif | |
157 | ) { | |
158 | av_log(avctx, AV_LOG_VERBOSE, | |
159 | "InitialDelayInKB: %"PRIu16"; TargetKbps: %"PRIu16"; MaxKbps: %"PRIu16"\n", | |
160 | info->InitialDelayInKB, info->TargetKbps, info->MaxKbps); | |
161 | } else if (info->RateControlMethod == MFX_RATECONTROL_CQP) { | |
162 | av_log(avctx, AV_LOG_VERBOSE, "QPI: %"PRIu16"; QPP: %"PRIu16"; QPB: %"PRIu16"\n", | |
163 | info->QPI, info->QPP, info->QPB); | |
164 | } else if (info->RateControlMethod == MFX_RATECONTROL_AVBR) { | |
165 | av_log(avctx, AV_LOG_VERBOSE, | |
166 | "TargetKbps: %"PRIu16"; Accuracy: %"PRIu16"; Convergence: %"PRIu16"\n", | |
167 | info->TargetKbps, info->Accuracy, info->Convergence); | |
168 | } | |
169 | #if QSV_HAVE_LA | |
170 | else if (info->RateControlMethod == MFX_RATECONTROL_LA | |
171 | #if QSV_HAVE_LA_HRD | |
172 | || info->RateControlMethod == MFX_RATECONTROL_LA_HRD | |
173 | #endif | |
174 | ) { | |
175 | av_log(avctx, AV_LOG_VERBOSE, | |
176 | "TargetKbps: %"PRIu16"; LookAheadDepth: %"PRIu16"\n", | |
177 | info->TargetKbps, co2->LookAheadDepth); | |
178 | } | |
179 | #endif | |
180 | #if QSV_HAVE_ICQ | |
181 | else if (info->RateControlMethod == MFX_RATECONTROL_ICQ) { | |
182 | av_log(avctx, AV_LOG_VERBOSE, "ICQQuality: %"PRIu16"\n", info->ICQQuality); | |
183 | } else if (info->RateControlMethod == MFX_RATECONTROL_LA_ICQ) { | |
184 | av_log(avctx, AV_LOG_VERBOSE, "ICQQuality: %"PRIu16"; LookAheadDepth: %"PRIu16"\n", | |
185 | info->ICQQuality, co2->LookAheadDepth); | |
186 | } | |
187 | #endif | |
188 | #if QSV_HAVE_QVBR | |
189 | else if (info->RateControlMethod == MFX_RATECONTROL_QVBR) { | |
190 | av_log(avctx, AV_LOG_VERBOSE, "QVBRQuality: %"PRIu16"\n", | |
191 | co3->QVBRQuality); | |
192 | } | |
193 | #endif | |
194 | ||
195 | av_log(avctx, AV_LOG_VERBOSE, "NumSlice: %"PRIu16"; NumRefFrame: %"PRIu16"\n", | |
196 | info->NumSlice, info->NumRefFrame); | |
197 | av_log(avctx, AV_LOG_VERBOSE, "RateDistortionOpt: %s\n", | |
198 | print_threestate(co->RateDistortionOpt)); | |
199 | ||
200 | #if QSV_HAVE_CO2 | |
201 | av_log(avctx, AV_LOG_VERBOSE, | |
202 | "RecoveryPointSEI: %s IntRefType: %"PRIu16"; IntRefCycleSize: %"PRIu16"; IntRefQPDelta: %"PRId16"\n", | |
203 | print_threestate(co->RecoveryPointSEI), co2->IntRefType, co2->IntRefCycleSize, co2->IntRefQPDelta); | |
204 | ||
205 | av_log(avctx, AV_LOG_VERBOSE, "MaxFrameSize: %"PRIu16"; ", co2->MaxFrameSize); | |
fc4c27c4 | 206 | #if QSV_HAVE_MAX_SLICE_SIZE |
4d8f536b AK |
207 | av_log(avctx, AV_LOG_VERBOSE, "MaxSliceSize: %"PRIu16"; ", co2->MaxSliceSize); |
208 | #endif | |
209 | av_log(avctx, AV_LOG_VERBOSE, "\n"); | |
210 | ||
211 | av_log(avctx, AV_LOG_VERBOSE, | |
212 | "BitrateLimit: %s; MBBRC: %s; ExtBRC: %s\n", | |
213 | print_threestate(co2->BitrateLimit), print_threestate(co2->MBBRC), | |
214 | print_threestate(co2->ExtBRC)); | |
215 | ||
216 | #if QSV_HAVE_TRELLIS | |
217 | av_log(avctx, AV_LOG_VERBOSE, "Trellis: "); | |
218 | if (co2->Trellis & MFX_TRELLIS_OFF) { | |
219 | av_log(avctx, AV_LOG_VERBOSE, "off"); | |
220 | } else if (!co2->Trellis) { | |
221 | av_log(avctx, AV_LOG_VERBOSE, "auto"); | |
222 | } else { | |
223 | if (co2->Trellis & MFX_TRELLIS_I) av_log(avctx, AV_LOG_VERBOSE, "I"); | |
224 | if (co2->Trellis & MFX_TRELLIS_P) av_log(avctx, AV_LOG_VERBOSE, "P"); | |
225 | if (co2->Trellis & MFX_TRELLIS_B) av_log(avctx, AV_LOG_VERBOSE, "B"); | |
226 | } | |
227 | av_log(avctx, AV_LOG_VERBOSE, "\n"); | |
228 | #endif | |
229 | ||
230 | #if QSV_VERSION_ATLEAST(1, 8) | |
231 | av_log(avctx, AV_LOG_VERBOSE, | |
232 | "RepeatPPS: %s; NumMbPerSlice: %"PRIu16"; LookAheadDS: ", | |
233 | print_threestate(co2->RepeatPPS), co2->NumMbPerSlice); | |
234 | switch (co2->LookAheadDS) { | |
235 | case MFX_LOOKAHEAD_DS_OFF: av_log(avctx, AV_LOG_VERBOSE, "off"); break; | |
236 | case MFX_LOOKAHEAD_DS_2x: av_log(avctx, AV_LOG_VERBOSE, "2x"); break; | |
237 | case MFX_LOOKAHEAD_DS_4x: av_log(avctx, AV_LOG_VERBOSE, "4x"); break; | |
238 | default: av_log(avctx, AV_LOG_VERBOSE, "unknown"); break; | |
239 | } | |
240 | av_log(avctx, AV_LOG_VERBOSE, "\n"); | |
241 | ||
242 | av_log(avctx, AV_LOG_VERBOSE, "AdaptiveI: %s; AdaptiveB: %s; BRefType: ", | |
243 | print_threestate(co2->AdaptiveI), print_threestate(co2->AdaptiveB)); | |
244 | switch (co2->BRefType) { | |
245 | case MFX_B_REF_OFF: av_log(avctx, AV_LOG_VERBOSE, "off"); break; | |
246 | case MFX_B_REF_PYRAMID: av_log(avctx, AV_LOG_VERBOSE, "pyramid"); break; | |
247 | default: av_log(avctx, AV_LOG_VERBOSE, "auto"); break; | |
248 | } | |
249 | av_log(avctx, AV_LOG_VERBOSE, "\n"); | |
250 | #endif | |
251 | ||
252 | #if QSV_VERSION_ATLEAST(1, 9) | |
253 | av_log(avctx, AV_LOG_VERBOSE, | |
254 | "MinQPI: %"PRIu8"; MaxQPI: %"PRIu8"; MinQPP: %"PRIu8"; MaxQPP: %"PRIu8"; MinQPB: %"PRIu8"; MaxQPB: %"PRIu8"\n", | |
255 | co2->MinQPI, co2->MaxQPI, co2->MinQPP, co2->MaxQPP, co2->MinQPB, co2->MaxQPB); | |
256 | #endif | |
257 | #endif | |
258 | ||
259 | if (avctx->codec_id == AV_CODEC_ID_H264) { | |
260 | av_log(avctx, AV_LOG_VERBOSE, "Entropy coding: %s; MaxDecFrameBuffering: %"PRIu16"\n", | |
261 | co->CAVLC == MFX_CODINGOPTION_ON ? "CAVLC" : "CABAC", co->MaxDecFrameBuffering); | |
262 | av_log(avctx, AV_LOG_VERBOSE, | |
263 | "NalHrdConformance: %s; SingleSeiNalUnit: %s; VuiVclHrdParameters: %s VuiNalHrdParameters: %s\n", | |
264 | print_threestate(co->NalHrdConformance), print_threestate(co->SingleSeiNalUnit), | |
265 | print_threestate(co->VuiVclHrdParameters), print_threestate(co->VuiNalHrdParameters)); | |
266 | } | |
267 | } | |
268 | ||
e7d7cf86 | 269 | static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) |
72b7441a | 270 | { |
e7d7cf86 AK |
271 | const char *rc_desc; |
272 | mfxU16 rc_mode; | |
273 | ||
274 | int want_la = q->la_depth >= 0; | |
275 | int want_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); | |
276 | int want_vcm = q->vcm; | |
277 | ||
278 | if (want_la && !QSV_HAVE_LA) { | |
279 | av_log(avctx, AV_LOG_ERROR, | |
280 | "Lookahead ratecontrol mode requested, but is not supported by this SDK version\n"); | |
281 | return AVERROR(ENOSYS); | |
282 | } | |
283 | if (want_vcm && !QSV_HAVE_VCM) { | |
284 | av_log(avctx, AV_LOG_ERROR, | |
285 | "VCM ratecontrol mode requested, but is not supported by this SDK version\n"); | |
286 | return AVERROR(ENOSYS); | |
287 | } | |
288 | ||
289 | if (want_la + want_qscale + want_vcm > 1) { | |
290 | av_log(avctx, AV_LOG_ERROR, | |
291 | "More than one of: { constant qscale, lookahead, VCM } requested, " | |
292 | "only one of them can be used at a time.\n"); | |
293 | return AVERROR(EINVAL); | |
294 | } | |
295 | ||
296 | if (want_qscale) { | |
297 | rc_mode = MFX_RATECONTROL_CQP; | |
298 | rc_desc = "constant quantization parameter (CQP)"; | |
299 | } | |
300 | #if QSV_HAVE_VCM | |
301 | else if (want_vcm) { | |
302 | rc_mode = MFX_RATECONTROL_VCM; | |
303 | rc_desc = "video conferencing mode (VCM)"; | |
304 | } | |
305 | #endif | |
306 | #if QSV_HAVE_LA | |
307 | else if (want_la) { | |
308 | rc_mode = MFX_RATECONTROL_LA; | |
309 | rc_desc = "VBR with lookahead (LA)"; | |
72b7441a | 310 | |
e7d7cf86 AK |
311 | #if QSV_HAVE_ICQ |
312 | if (avctx->global_quality > 0) { | |
313 | rc_mode = MFX_RATECONTROL_LA_ICQ; | |
314 | rc_desc = "intelligent constant quality with lookahead (LA_ICQ)"; | |
315 | } | |
316 | #endif | |
317 | } | |
318 | #endif | |
319 | #if QSV_HAVE_ICQ | |
320 | else if (avctx->global_quality > 0) { | |
321 | rc_mode = MFX_RATECONTROL_ICQ; | |
322 | rc_desc = "intelligent constant quality (ICQ)"; | |
323 | } | |
324 | #endif | |
325 | else if (avctx->rc_max_rate == avctx->bit_rate) { | |
326 | rc_mode = MFX_RATECONTROL_CBR; | |
327 | rc_desc = "constant bitrate (CBR)"; | |
328 | } else if (!avctx->rc_max_rate) { | |
329 | rc_mode = MFX_RATECONTROL_AVBR; | |
330 | rc_desc = "average variable bitrate (AVBR)"; | |
331 | } else { | |
332 | rc_mode = MFX_RATECONTROL_VBR; | |
333 | rc_desc = "variable bitrate (VBR)"; | |
334 | } | |
335 | ||
336 | q->param.mfx.RateControlMethod = rc_mode; | |
337 | av_log(avctx, AV_LOG_VERBOSE, "Using the %s ratecontrol method\n", rc_desc); | |
338 | ||
339 | return 0; | |
340 | } | |
341 | ||
342 | static int rc_supported(QSVEncContext *q) | |
343 | { | |
344 | mfxVideoParam param_out = { .mfx.CodecId = q->param.mfx.CodecId }; | |
345 | mfxStatus ret; | |
346 | ||
347 | ret = MFXVideoENCODE_Query(q->session, &q->param, ¶m_out); | |
348 | if (ret < 0 || | |
349 | param_out.mfx.RateControlMethod != q->param.mfx.RateControlMethod) | |
350 | return 0; | |
351 | return 1; | |
352 | } | |
353 | ||
354 | static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) | |
355 | { | |
72b7441a AK |
356 | float quant; |
357 | int ret; | |
358 | ||
359 | ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); | |
360 | if (ret < 0) | |
361 | return AVERROR_BUG; | |
362 | q->param.mfx.CodecId = ret; | |
363 | ||
66acb76b AK |
364 | q->width_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16; |
365 | ||
72b7441a AK |
366 | if (avctx->level > 0) |
367 | q->param.mfx.CodecLevel = avctx->level; | |
368 | ||
369 | q->param.mfx.CodecProfile = q->profile; | |
370 | q->param.mfx.TargetUsage = q->preset; | |
371 | q->param.mfx.GopPicSize = FFMAX(0, avctx->gop_size); | |
372 | q->param.mfx.GopRefDist = FFMAX(-1, avctx->max_b_frames) + 1; | |
7c6eb0a1 | 373 | q->param.mfx.GopOptFlag = avctx->flags & AV_CODEC_FLAG_CLOSED_GOP ? |
72b7441a AK |
374 | MFX_GOP_CLOSED : 0; |
375 | q->param.mfx.IdrInterval = q->idr_interval; | |
376 | q->param.mfx.NumSlice = avctx->slices; | |
377 | q->param.mfx.NumRefFrame = FFMAX(0, avctx->refs); | |
378 | q->param.mfx.EncodedOrder = 0; | |
379 | q->param.mfx.BufferSizeInKB = 0; | |
380 | ||
381 | q->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; | |
66acb76b | 382 | q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, q->width_align); |
72b7441a AK |
383 | q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, 32); |
384 | q->param.mfx.FrameInfo.CropX = 0; | |
385 | q->param.mfx.FrameInfo.CropY = 0; | |
386 | q->param.mfx.FrameInfo.CropW = avctx->width; | |
387 | q->param.mfx.FrameInfo.CropH = avctx->height; | |
388 | q->param.mfx.FrameInfo.AspectRatioW = avctx->sample_aspect_ratio.num; | |
389 | q->param.mfx.FrameInfo.AspectRatioH = avctx->sample_aspect_ratio.den; | |
390 | q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; | |
391 | q->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; | |
392 | q->param.mfx.FrameInfo.BitDepthLuma = 8; | |
393 | q->param.mfx.FrameInfo.BitDepthChroma = 8; | |
394 | ||
395 | if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { | |
396 | q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num; | |
397 | q->param.mfx.FrameInfo.FrameRateExtD = avctx->framerate.den; | |
398 | } else { | |
399 | q->param.mfx.FrameInfo.FrameRateExtN = avctx->time_base.den; | |
400 | q->param.mfx.FrameInfo.FrameRateExtD = avctx->time_base.num; | |
401 | } | |
402 | ||
e7d7cf86 AK |
403 | ret = select_rc_mode(avctx, q); |
404 | if (ret < 0) | |
405 | return ret; | |
72b7441a AK |
406 | |
407 | switch (q->param.mfx.RateControlMethod) { | |
408 | case MFX_RATECONTROL_CBR: | |
409 | case MFX_RATECONTROL_VBR: | |
e7d7cf86 AK |
410 | #if QSV_HAVE_VCM |
411 | case MFX_RATECONTROL_VCM: | |
412 | #endif | |
72b7441a AK |
413 | q->param.mfx.InitialDelayInKB = avctx->rc_initial_buffer_occupancy / 1000; |
414 | q->param.mfx.TargetKbps = avctx->bit_rate / 1000; | |
3edac01f | 415 | q->param.mfx.MaxKbps = avctx->rc_max_rate / 1000; |
72b7441a AK |
416 | break; |
417 | case MFX_RATECONTROL_CQP: | |
418 | quant = avctx->global_quality / FF_QP2LAMBDA; | |
419 | ||
420 | q->param.mfx.QPI = av_clip(quant * fabs(avctx->i_quant_factor) + avctx->i_quant_offset, 0, 51); | |
421 | q->param.mfx.QPP = av_clip(quant, 0, 51); | |
422 | q->param.mfx.QPB = av_clip(quant * fabs(avctx->b_quant_factor) + avctx->b_quant_offset, 0, 51); | |
423 | ||
424 | break; | |
425 | case MFX_RATECONTROL_AVBR: | |
426 | q->param.mfx.TargetKbps = avctx->bit_rate / 1000; | |
427 | q->param.mfx.Convergence = q->avbr_convergence; | |
428 | q->param.mfx.Accuracy = q->avbr_accuracy; | |
429 | break; | |
e7d7cf86 AK |
430 | #if QSV_HAVE_LA |
431 | case MFX_RATECONTROL_LA: | |
432 | q->param.mfx.TargetKbps = avctx->bit_rate / 1000; | |
433 | q->extco2.LookAheadDepth = q->la_depth; | |
434 | break; | |
435 | #if QSV_HAVE_ICQ | |
436 | case MFX_RATECONTROL_LA_ICQ: | |
437 | q->extco2.LookAheadDepth = q->la_depth; | |
438 | case MFX_RATECONTROL_ICQ: | |
439 | q->param.mfx.ICQQuality = avctx->global_quality; | |
440 | break; | |
441 | #endif | |
442 | #endif | |
72b7441a AK |
443 | } |
444 | ||
66acb76b AK |
445 | // the HEVC encoder plugin currently fails if coding options |
446 | // are provided | |
447 | if (avctx->codec_id != AV_CODEC_ID_HEVC) { | |
448 | q->extco.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; | |
449 | q->extco.Header.BufferSz = sizeof(q->extco); | |
9cac1b4b VG |
450 | #if FF_API_CODER_TYPE |
451 | FF_DISABLE_DEPRECATION_WARNINGS | |
452 | if (avctx->coder_type != 0) | |
453 | q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC; | |
454 | FF_ENABLE_DEPRECATION_WARNINGS | |
455 | #endif | |
456 | q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON | |
457 | : MFX_CODINGOPTION_UNKNOWN; | |
72b7441a | 458 | |
fc4c27c4 AK |
459 | if (q->rdo >= 0) |
460 | q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
461 | ||
462 | if (avctx->codec_id == AV_CODEC_ID_H264) { | |
463 | if (avctx->strict_std_compliance != FF_COMPLIANCE_NORMAL) | |
464 | q->extco.NalHrdConformance = avctx->strict_std_compliance > FF_COMPLIANCE_NORMAL ? | |
465 | MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
466 | ||
467 | if (q->single_sei_nal_unit >= 0) | |
468 | q->extco.SingleSeiNalUnit = q->single_sei_nal_unit ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
469 | if (q->recovery_point_sei >= 0) | |
470 | q->extco.RecoveryPointSEI = q->recovery_point_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
471 | q->extco.MaxDecFrameBuffering = q->max_dec_frame_buffering; | |
472 | } | |
473 | ||
dc923bc2 | 474 | q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco; |
e7d7cf86 AK |
475 | |
476 | #if QSV_HAVE_CO2 | |
477 | if (avctx->codec_id == AV_CODEC_ID_H264) { | |
478 | q->extco2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; | |
479 | q->extco2.Header.BufferSz = sizeof(q->extco2); | |
fc4c27c4 AK |
480 | |
481 | if (q->int_ref_type >= 0) | |
482 | q->extco2.IntRefType = q->int_ref_type; | |
483 | if (q->int_ref_cycle_size >= 0) | |
484 | q->extco2.IntRefCycleSize = q->int_ref_cycle_size; | |
485 | if (q->int_ref_qp_delta != INT16_MIN) | |
486 | q->extco2.IntRefQPDelta = q->int_ref_qp_delta; | |
487 | ||
488 | if (q->bitrate_limit >= 0) | |
489 | q->extco2.BitrateLimit = q->bitrate_limit ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
490 | if (q->mbbrc >= 0) | |
491 | q->extco2.MBBRC = q->mbbrc ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
492 | if (q->extbrc >= 0) | |
493 | q->extco2.ExtBRC = q->extbrc ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
494 | ||
495 | if (q->max_frame_size >= 0) | |
496 | q->extco2.MaxFrameSize = q->max_frame_size; | |
497 | #if QSV_HAVE_MAX_SLICE_SIZE | |
498 | if (q->max_slice_size >= 0) | |
499 | q->extco2.MaxSliceSize = q->max_slice_size; | |
500 | #endif | |
501 | ||
502 | #if QSV_HAVE_TRELLIS | |
503 | q->extco2.Trellis = q->trellis; | |
504 | #endif | |
505 | ||
506 | #if QSV_HAVE_BREF_TYPE | |
0e6c8532 VG |
507 | #if FF_API_PRIVATE_OPT |
508 | FF_DISABLE_DEPRECATION_WARNINGS | |
fc4c27c4 | 509 | if (avctx->b_frame_strategy >= 0) |
0e6c8532 VG |
510 | q->b_strategy = avctx->b_frame_strategy; |
511 | FF_ENABLE_DEPRECATION_WARNINGS | |
512 | #endif | |
68395f8c | 513 | if (q->b_strategy >= 0) |
0e6c8532 | 514 | q->extco2.BRefType = q->b_strategy ? MFX_B_REF_PYRAMID : MFX_B_REF_OFF; |
fc4c27c4 AK |
515 | if (q->adaptive_i >= 0) |
516 | q->extco2.AdaptiveI = q->adaptive_i ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
517 | if (q->adaptive_b >= 0) | |
518 | q->extco2.AdaptiveB = q->adaptive_b ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; | |
519 | #endif | |
520 | ||
e7d7cf86 AK |
521 | q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2; |
522 | } | |
523 | #endif | |
524 | } | |
525 | ||
526 | if (!rc_supported(q)) { | |
527 | av_log(avctx, AV_LOG_ERROR, | |
528 | "Selected ratecontrol mode is not supported by the QSV " | |
529 | "runtime. Choose a different mode.\n"); | |
530 | return AVERROR(ENOSYS); | |
66acb76b | 531 | } |
72b7441a AK |
532 | |
533 | return 0; | |
534 | } | |
535 | ||
536 | static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) | |
537 | { | |
82590024 AK |
538 | AVCPBProperties *cpb_props; |
539 | ||
72b7441a AK |
540 | uint8_t sps_buf[128]; |
541 | uint8_t pps_buf[128]; | |
542 | ||
543 | mfxExtCodingOptionSPSPPS extradata = { | |
544 | .Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS, | |
545 | .Header.BufferSz = sizeof(extradata), | |
546 | .SPSBuffer = sps_buf, .SPSBufSize = sizeof(sps_buf), | |
547 | .PPSBuffer = pps_buf, .PPSBufSize = sizeof(pps_buf) | |
548 | }; | |
549 | ||
4d8f536b AK |
550 | mfxExtCodingOption co = { |
551 | .Header.BufferId = MFX_EXTBUFF_CODING_OPTION, | |
552 | .Header.BufferSz = sizeof(co), | |
553 | }; | |
554 | #if QSV_HAVE_CO2 | |
555 | mfxExtCodingOption2 co2 = { | |
556 | .Header.BufferId = MFX_EXTBUFF_CODING_OPTION2, | |
557 | .Header.BufferSz = sizeof(co2), | |
558 | }; | |
559 | #endif | |
560 | #if QSV_HAVE_CO3 | |
561 | mfxExtCodingOption3 co3 = { | |
562 | .Header.BufferId = MFX_EXTBUFF_CODING_OPTION3, | |
563 | .Header.BufferSz = sizeof(co3), | |
564 | }; | |
565 | #endif | |
566 | ||
72b7441a AK |
567 | mfxExtBuffer *ext_buffers[] = { |
568 | (mfxExtBuffer*)&extradata, | |
4d8f536b AK |
569 | (mfxExtBuffer*)&co, |
570 | #if QSV_HAVE_CO2 | |
571 | (mfxExtBuffer*)&co2, | |
572 | #endif | |
573 | #if QSV_HAVE_CO3 | |
574 | (mfxExtBuffer*)&co3, | |
575 | #endif | |
72b7441a AK |
576 | }; |
577 | ||
3a85397e | 578 | int need_pps = avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO; |
72b7441a AK |
579 | int ret; |
580 | ||
581 | q->param.ExtParam = ext_buffers; | |
582 | q->param.NumExtParam = FF_ARRAY_ELEMS(ext_buffers); | |
583 | ||
584 | ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); | |
585 | if (ret < 0) | |
586 | return ff_qsv_error(ret); | |
587 | ||
588 | q->packet_size = q->param.mfx.BufferSizeInKB * 1000; | |
589 | ||
3a85397e | 590 | if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize)) { |
72b7441a AK |
591 | av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx.\n"); |
592 | return AVERROR_UNKNOWN; | |
593 | } | |
594 | ||
3a85397e | 595 | avctx->extradata = av_malloc(extradata.SPSBufSize + need_pps * extradata.PPSBufSize + |
059a9348 | 596 | AV_INPUT_BUFFER_PADDING_SIZE); |
72b7441a AK |
597 | if (!avctx->extradata) |
598 | return AVERROR(ENOMEM); | |
599 | ||
600 | memcpy(avctx->extradata, sps_buf, extradata.SPSBufSize); | |
3a85397e AK |
601 | if (need_pps) |
602 | memcpy(avctx->extradata + extradata.SPSBufSize, pps_buf, extradata.PPSBufSize); | |
603 | avctx->extradata_size = extradata.SPSBufSize + need_pps * extradata.PPSBufSize; | |
059a9348 | 604 | memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
72b7441a | 605 | |
82590024 AK |
606 | cpb_props = ff_add_cpb_side_data(avctx); |
607 | if (!cpb_props) | |
608 | return AVERROR(ENOMEM); | |
609 | cpb_props->max_bitrate = avctx->rc_max_rate; | |
610 | cpb_props->min_bitrate = avctx->rc_min_rate; | |
611 | cpb_props->avg_bitrate = avctx->bit_rate; | |
612 | cpb_props->buffer_size = avctx->rc_buffer_size; | |
613 | ||
4d8f536b AK |
614 | dump_video_param(avctx, q, ext_buffers + 1); |
615 | ||
72b7441a AK |
616 | return 0; |
617 | } | |
618 | ||
dc923bc2 AK |
619 | static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q) |
620 | { | |
621 | AVQSVContext *qsv = avctx->hwaccel_context; | |
622 | mfxFrameSurface1 *surfaces; | |
623 | int nb_surfaces, i; | |
624 | ||
625 | nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested + q->async_depth; | |
626 | ||
627 | q->opaque_alloc_buf = av_buffer_allocz(sizeof(*surfaces) * nb_surfaces); | |
628 | if (!q->opaque_alloc_buf) | |
629 | return AVERROR(ENOMEM); | |
630 | ||
631 | q->opaque_surfaces = av_malloc_array(nb_surfaces, sizeof(*q->opaque_surfaces)); | |
632 | if (!q->opaque_surfaces) | |
633 | return AVERROR(ENOMEM); | |
634 | ||
635 | surfaces = (mfxFrameSurface1*)q->opaque_alloc_buf->data; | |
636 | for (i = 0; i < nb_surfaces; i++) { | |
637 | surfaces[i].Info = q->req.Info; | |
638 | q->opaque_surfaces[i] = surfaces + i; | |
639 | } | |
640 | ||
641 | q->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; | |
642 | q->opaque_alloc.Header.BufferSz = sizeof(q->opaque_alloc); | |
643 | q->opaque_alloc.In.Surfaces = q->opaque_surfaces; | |
644 | q->opaque_alloc.In.NumSurface = nb_surfaces; | |
645 | q->opaque_alloc.In.Type = q->req.Type; | |
646 | ||
647 | q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->opaque_alloc; | |
648 | ||
649 | qsv->nb_opaque_surfaces = nb_surfaces; | |
650 | qsv->opaque_surfaces = q->opaque_alloc_buf; | |
651 | qsv->opaque_alloc_type = q->req.Type; | |
652 | ||
653 | return 0; | |
654 | } | |
655 | ||
72b7441a AK |
656 | int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) |
657 | { | |
dc923bc2 | 658 | int opaque_alloc = 0; |
72b7441a AK |
659 | int ret; |
660 | ||
661 | q->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; | |
662 | q->param.AsyncDepth = q->async_depth; | |
663 | ||
69b92f1b | 664 | q->async_fifo = av_fifo_alloc((1 + q->async_depth) * |
a1335149 | 665 | (sizeof(AVPacket) + sizeof(mfxSyncPoint*) + sizeof(mfxBitstream*))); |
69b92f1b AK |
666 | if (!q->async_fifo) |
667 | return AVERROR(ENOMEM); | |
668 | ||
72b7441a AK |
669 | if (avctx->hwaccel_context) { |
670 | AVQSVContext *qsv = avctx->hwaccel_context; | |
671 | ||
672 | q->session = qsv->session; | |
673 | q->param.IOPattern = qsv->iopattern; | |
dc923bc2 AK |
674 | |
675 | opaque_alloc = qsv->opaque_alloc; | |
72b7441a AK |
676 | } |
677 | ||
678 | if (!q->session) { | |
66acb76b AK |
679 | ret = ff_qsv_init_internal_session(avctx, &q->internal_session, |
680 | q->load_plugins); | |
72b7441a AK |
681 | if (ret < 0) |
682 | return ret; | |
683 | ||
684 | q->session = q->internal_session; | |
685 | } | |
686 | ||
687 | ret = init_video_param(avctx, q); | |
688 | if (ret < 0) | |
689 | return ret; | |
690 | ||
691 | ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req); | |
692 | if (ret < 0) { | |
693 | av_log(avctx, AV_LOG_ERROR, "Error querying the encoding parameters\n"); | |
694 | return ff_qsv_error(ret); | |
695 | } | |
696 | ||
dc923bc2 AK |
697 | if (opaque_alloc) { |
698 | ret = qsv_init_opaque_alloc(avctx, q); | |
699 | if (ret < 0) | |
700 | return ret; | |
701 | } | |
702 | ||
772c87c5 AK |
703 | if (avctx->hwaccel_context) { |
704 | AVQSVContext *qsv = avctx->hwaccel_context; | |
705 | int i, j; | |
706 | ||
dc923bc2 | 707 | q->extparam = av_mallocz_array(qsv->nb_ext_buffers + q->nb_extparam_internal, |
772c87c5 AK |
708 | sizeof(*q->extparam)); |
709 | if (!q->extparam) | |
710 | return AVERROR(ENOMEM); | |
711 | ||
712 | q->param.ExtParam = q->extparam; | |
713 | for (i = 0; i < qsv->nb_ext_buffers; i++) | |
714 | q->param.ExtParam[i] = qsv->ext_buffers[i]; | |
715 | q->param.NumExtParam = qsv->nb_ext_buffers; | |
716 | ||
dc923bc2 | 717 | for (i = 0; i < q->nb_extparam_internal; i++) { |
772c87c5 AK |
718 | for (j = 0; j < qsv->nb_ext_buffers; j++) { |
719 | if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId) | |
720 | break; | |
721 | } | |
722 | if (j < qsv->nb_ext_buffers) | |
723 | continue; | |
724 | ||
725 | q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i]; | |
726 | } | |
727 | } else { | |
728 | q->param.ExtParam = q->extparam_internal; | |
dc923bc2 | 729 | q->param.NumExtParam = q->nb_extparam_internal; |
772c87c5 AK |
730 | } |
731 | ||
72b7441a AK |
732 | ret = MFXVideoENCODE_Init(q->session, &q->param); |
733 | if (ret < 0) { | |
734 | av_log(avctx, AV_LOG_ERROR, "Error initializing the encoder\n"); | |
735 | return ff_qsv_error(ret); | |
736 | } | |
737 | ||
738 | ret = qsv_retrieve_enc_params(avctx, q); | |
739 | if (ret < 0) { | |
740 | av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); | |
741 | return ret; | |
742 | } | |
743 | ||
72b7441a AK |
744 | q->avctx = avctx; |
745 | ||
746 | return 0; | |
747 | } | |
748 | ||
749 | static void clear_unused_frames(QSVEncContext *q) | |
750 | { | |
751 | QSVFrame *cur = q->work_frames; | |
752 | while (cur) { | |
753 | if (cur->surface && !cur->surface->Data.Locked) { | |
754 | cur->surface = NULL; | |
755 | av_frame_unref(cur->frame); | |
756 | } | |
757 | cur = cur->next; | |
758 | } | |
759 | } | |
760 | ||
761 | static int get_free_frame(QSVEncContext *q, QSVFrame **f) | |
762 | { | |
763 | QSVFrame *frame, **last; | |
764 | ||
765 | clear_unused_frames(q); | |
766 | ||
767 | frame = q->work_frames; | |
768 | last = &q->work_frames; | |
769 | while (frame) { | |
770 | if (!frame->surface) { | |
771 | *f = frame; | |
772 | return 0; | |
773 | } | |
774 | ||
775 | last = &frame->next; | |
776 | frame = frame->next; | |
777 | } | |
778 | ||
779 | frame = av_mallocz(sizeof(*frame)); | |
780 | if (!frame) | |
781 | return AVERROR(ENOMEM); | |
782 | frame->frame = av_frame_alloc(); | |
783 | if (!frame->frame) { | |
784 | av_freep(&frame); | |
785 | return AVERROR(ENOMEM); | |
786 | } | |
787 | *last = frame; | |
788 | ||
789 | *f = frame; | |
790 | ||
791 | return 0; | |
792 | } | |
793 | ||
794 | static int submit_frame(QSVEncContext *q, const AVFrame *frame, | |
795 | mfxFrameSurface1 **surface) | |
796 | { | |
797 | QSVFrame *qf; | |
798 | int ret; | |
799 | ||
800 | ret = get_free_frame(q, &qf); | |
801 | if (ret < 0) | |
802 | return ret; | |
803 | ||
804 | if (frame->format == AV_PIX_FMT_QSV) { | |
805 | ret = av_frame_ref(qf->frame, frame); | |
806 | if (ret < 0) | |
807 | return ret; | |
808 | ||
809 | qf->surface = (mfxFrameSurface1*)qf->frame->data[3]; | |
f6f32fc9 | 810 | } else { |
2ec96b6b AK |
811 | /* make a copy if the input is not padded as libmfx requires */ |
812 | if (frame->height & 31 || frame->linesize[0] & (q->width_align - 1)) { | |
813 | qf->frame->height = FFALIGN(frame->height, 32); | |
814 | qf->frame->width = FFALIGN(frame->width, q->width_align); | |
815 | ||
816 | ret = ff_get_buffer(q->avctx, qf->frame, AV_GET_BUFFER_FLAG_REF); | |
817 | if (ret < 0) | |
818 | return ret; | |
819 | ||
820 | qf->frame->height = frame->height; | |
821 | qf->frame->width = frame->width; | |
822 | ret = av_frame_copy(qf->frame, frame); | |
823 | if (ret < 0) { | |
824 | av_frame_unref(qf->frame); | |
825 | return ret; | |
826 | } | |
827 | } else { | |
828 | ret = av_frame_ref(qf->frame, frame); | |
829 | if (ret < 0) | |
830 | return ret; | |
72b7441a | 831 | } |
72b7441a | 832 | |
2ec96b6b | 833 | qf->surface_internal.Info = q->param.mfx.FrameInfo; |
72b7441a | 834 | |
2ec96b6b AK |
835 | qf->surface_internal.Info.PicStruct = |
836 | !frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE : | |
837 | frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : | |
838 | MFX_PICSTRUCT_FIELD_BFF; | |
839 | if (frame->repeat_pict == 1) | |
840 | qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED; | |
841 | else if (frame->repeat_pict == 2) | |
842 | qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING; | |
843 | else if (frame->repeat_pict == 4) | |
844 | qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING; | |
72b7441a | 845 | |
2ec96b6b AK |
846 | qf->surface_internal.Data.PitchLow = qf->frame->linesize[0]; |
847 | qf->surface_internal.Data.Y = qf->frame->data[0]; | |
848 | qf->surface_internal.Data.UV = qf->frame->data[1]; | |
72b7441a | 849 | |
2ec96b6b | 850 | qf->surface = &qf->surface_internal; |
f6f32fc9 AK |
851 | } |
852 | ||
853 | qf->surface->Data.TimeStamp = av_rescale_q(frame->pts, q->avctx->time_base, (AVRational){1, 90000}); | |
72b7441a AK |
854 | |
855 | *surface = qf->surface; | |
856 | ||
857 | return 0; | |
858 | } | |
859 | ||
860 | static void print_interlace_msg(AVCodecContext *avctx, QSVEncContext *q) | |
861 | { | |
862 | if (q->param.mfx.CodecId == MFX_CODEC_AVC) { | |
863 | if (q->param.mfx.CodecProfile == MFX_PROFILE_AVC_BASELINE || | |
864 | q->param.mfx.CodecLevel < MFX_LEVEL_AVC_21 || | |
865 | q->param.mfx.CodecLevel > MFX_LEVEL_AVC_41) | |
866 | av_log(avctx, AV_LOG_WARNING, | |
867 | "Interlaced coding is supported" | |
868 | " at Main/High Profile Level 2.1-4.1\n"); | |
869 | } | |
870 | } | |
871 | ||
d1cd20e4 AK |
872 | static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, |
873 | const AVFrame *frame) | |
72b7441a | 874 | { |
69b92f1b AK |
875 | AVPacket new_pkt = { 0 }; |
876 | mfxBitstream *bs; | |
72b7441a AK |
877 | |
878 | mfxFrameSurface1 *surf = NULL; | |
a1335149 | 879 | mfxSyncPoint *sync = NULL; |
72b7441a AK |
880 | int ret; |
881 | ||
882 | if (frame) { | |
883 | ret = submit_frame(q, frame, &surf); | |
884 | if (ret < 0) { | |
885 | av_log(avctx, AV_LOG_ERROR, "Error submitting the frame for encoding.\n"); | |
886 | return ret; | |
887 | } | |
888 | } | |
889 | ||
69b92f1b | 890 | ret = av_new_packet(&new_pkt, q->packet_size); |
72b7441a AK |
891 | if (ret < 0) { |
892 | av_log(avctx, AV_LOG_ERROR, "Error allocating the output packet\n"); | |
893 | return ret; | |
894 | } | |
69b92f1b AK |
895 | |
896 | bs = av_mallocz(sizeof(*bs)); | |
897 | if (!bs) { | |
898 | av_packet_unref(&new_pkt); | |
899 | return AVERROR(ENOMEM); | |
900 | } | |
901 | bs->Data = new_pkt.data; | |
902 | bs->MaxLength = new_pkt.size; | |
72b7441a | 903 | |
a1335149 MD |
904 | sync = av_mallocz(sizeof(*sync)); |
905 | if (!sync) { | |
906 | av_freep(&bs); | |
907 | av_packet_unref(&new_pkt); | |
908 | return AVERROR(ENOMEM); | |
909 | } | |
910 | ||
72b7441a | 911 | do { |
a1335149 | 912 | ret = MFXVideoENCODE_EncodeFrameAsync(q->session, NULL, surf, bs, sync); |
72b7441a AK |
913 | if (ret == MFX_WRN_DEVICE_BUSY) |
914 | av_usleep(1); | |
915 | } while (ret > 0); | |
916 | ||
69b92f1b AK |
917 | if (ret < 0) { |
918 | av_packet_unref(&new_pkt); | |
919 | av_freep(&bs); | |
a1335149 | 920 | av_freep(&sync); |
72b7441a | 921 | return (ret == MFX_ERR_MORE_DATA) ? 0 : ff_qsv_error(ret); |
69b92f1b | 922 | } |
72b7441a AK |
923 | |
924 | if (ret == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM && frame->interlaced_frame) | |
925 | print_interlace_msg(avctx, q); | |
926 | ||
a1335149 | 927 | if (*sync) { |
69b92f1b AK |
928 | av_fifo_generic_write(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL); |
929 | av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); | |
930 | av_fifo_generic_write(q->async_fifo, &bs, sizeof(bs), NULL); | |
931 | } else { | |
a1335149 | 932 | av_freep(&sync); |
69b92f1b AK |
933 | av_packet_unref(&new_pkt); |
934 | av_freep(&bs); | |
935 | } | |
936 | ||
d1cd20e4 AK |
937 | return 0; |
938 | } | |
939 | ||
940 | int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q, | |
941 | AVPacket *pkt, const AVFrame *frame, int *got_packet) | |
942 | { | |
943 | int ret; | |
944 | ||
945 | ret = encode_frame(avctx, q, frame); | |
946 | if (ret < 0) | |
947 | return ret; | |
948 | ||
69b92f1b AK |
949 | if (!av_fifo_space(q->async_fifo) || |
950 | (!frame && av_fifo_size(q->async_fifo))) { | |
d1cd20e4 AK |
951 | AVPacket new_pkt; |
952 | mfxBitstream *bs; | |
a1335149 | 953 | mfxSyncPoint *sync; |
d1cd20e4 | 954 | |
69b92f1b AK |
955 | av_fifo_generic_read(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL); |
956 | av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); | |
957 | av_fifo_generic_read(q->async_fifo, &bs, sizeof(bs), NULL); | |
958 | ||
a6259a6e | 959 | do { |
a1335149 | 960 | ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000); |
a6259a6e | 961 | } while (ret == MFX_WRN_IN_EXECUTION); |
72b7441a | 962 | |
69b92f1b AK |
963 | new_pkt.dts = av_rescale_q(bs->DecodeTimeStamp, (AVRational){1, 90000}, avctx->time_base); |
964 | new_pkt.pts = av_rescale_q(bs->TimeStamp, (AVRational){1, 90000}, avctx->time_base); | |
965 | new_pkt.size = bs->DataLength; | |
966 | ||
967 | if (bs->FrameType & MFX_FRAMETYPE_IDR || | |
968 | bs->FrameType & MFX_FRAMETYPE_xIDR) | |
969 | new_pkt.flags |= AV_PKT_FLAG_KEY; | |
970 | ||
40cf1bba VG |
971 | #if FF_API_CODED_FRAME |
972 | FF_DISABLE_DEPRECATION_WARNINGS | |
69b92f1b | 973 | if (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & MFX_FRAMETYPE_xI) |
72b7441a | 974 | avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; |
69b92f1b | 975 | else if (bs->FrameType & MFX_FRAMETYPE_P || bs->FrameType & MFX_FRAMETYPE_xP) |
72b7441a | 976 | avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P; |
69b92f1b | 977 | else if (bs->FrameType & MFX_FRAMETYPE_B || bs->FrameType & MFX_FRAMETYPE_xB) |
72b7441a | 978 | avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B; |
40cf1bba VG |
979 | FF_ENABLE_DEPRECATION_WARNINGS |
980 | #endif | |
72b7441a | 981 | |
69b92f1b | 982 | av_freep(&bs); |
a1335149 | 983 | av_freep(&sync); |
69b92f1b AK |
984 | |
985 | if (pkt->data) { | |
986 | if (pkt->size < new_pkt.size) { | |
987 | av_log(avctx, AV_LOG_ERROR, "Submitted buffer not large enough: %d < %d\n", | |
988 | pkt->size, new_pkt.size); | |
989 | av_packet_unref(&new_pkt); | |
990 | return AVERROR(EINVAL); | |
991 | } | |
72b7441a | 992 | |
69b92f1b AK |
993 | memcpy(pkt->data, new_pkt.data, new_pkt.size); |
994 | pkt->size = new_pkt.size; | |
995 | ||
996 | ret = av_packet_copy_props(pkt, &new_pkt); | |
997 | av_packet_unref(&new_pkt); | |
998 | if (ret < 0) | |
999 | return ret; | |
1000 | } else | |
1001 | *pkt = new_pkt; | |
72b7441a AK |
1002 | |
1003 | *got_packet = 1; | |
1004 | } | |
1005 | ||
1006 | return 0; | |
1007 | } | |
1008 | ||
1009 | int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q) | |
1010 | { | |
1011 | QSVFrame *cur; | |
1012 | ||
83847cc8 AK |
1013 | if (q->session) |
1014 | MFXVideoENCODE_Close(q->session); | |
72b7441a AK |
1015 | if (q->internal_session) |
1016 | MFXClose(q->internal_session); | |
1017 | q->session = NULL; | |
1018 | q->internal_session = NULL; | |
1019 | ||
1020 | cur = q->work_frames; | |
1021 | while (cur) { | |
1022 | q->work_frames = cur->next; | |
1023 | av_frame_free(&cur->frame); | |
1024 | av_freep(&cur); | |
1025 | cur = q->work_frames; | |
1026 | } | |
1027 | ||
69b92f1b AK |
1028 | while (q->async_fifo && av_fifo_size(q->async_fifo)) { |
1029 | AVPacket pkt; | |
a1335149 | 1030 | mfxSyncPoint *sync; |
69b92f1b AK |
1031 | mfxBitstream *bs; |
1032 | ||
1033 | av_fifo_generic_read(q->async_fifo, &pkt, sizeof(pkt), NULL); | |
1034 | av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); | |
1035 | av_fifo_generic_read(q->async_fifo, &bs, sizeof(bs), NULL); | |
1036 | ||
a1335149 | 1037 | av_freep(&sync); |
69b92f1b AK |
1038 | av_freep(&bs); |
1039 | av_packet_unref(&pkt); | |
1040 | } | |
1041 | av_fifo_free(q->async_fifo); | |
1042 | q->async_fifo = NULL; | |
1043 | ||
dc923bc2 AK |
1044 | av_freep(&q->opaque_surfaces); |
1045 | av_buffer_unref(&q->opaque_alloc_buf); | |
1046 | ||
772c87c5 AK |
1047 | av_freep(&q->extparam); |
1048 | ||
72b7441a AK |
1049 | return 0; |
1050 | } |