blob: fbddfa5d5a8ee83e16b42f9e890db0b0242becc8
1 | /* |
2 | * This file is part of FFmpeg. |
3 | * |
4 | * FFmpeg is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * FFmpeg is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with FFmpeg; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #include <va/va.h> |
20 | #include <va/va_enc_mpeg2.h> |
21 | |
22 | #include "libavutil/avassert.h" |
23 | #include "libavutil/common.h" |
24 | #include "libavutil/internal.h" |
25 | #include "libavutil/opt.h" |
26 | #include "libavutil/pixfmt.h" |
27 | |
28 | #include "avcodec.h" |
29 | #include "internal.h" |
30 | #include "mpegvideo.h" |
31 | #include "put_bits.h" |
32 | #include "vaapi_encode.h" |
33 | |
34 | typedef struct VAAPIEncodeMPEG2Context { |
35 | int mb_width; |
36 | int mb_height; |
37 | |
38 | int quant_i; |
39 | int quant_p; |
40 | int quant_b; |
41 | |
42 | int64_t last_i_frame; |
43 | |
44 | unsigned int bit_rate; |
45 | unsigned int vbv_buffer_size; |
46 | } VAAPIEncodeMPEG2Context; |
47 | |
48 | |
49 | #define vseq_var(name) vseq->name, name |
50 | #define vseqext_field(name) vseq->sequence_extension.bits.name, name |
51 | #define vgop_field(name) vseq->gop_header.bits.name, name |
52 | #define vpic_var(name) vpic->name, name |
53 | #define vpcext_field(name) vpic->picture_coding_extension.bits.name, name |
54 | #define vcomp_field(name) vpic->composite_display.bits.name, name |
55 | |
56 | #define u2(width, value, name) put_bits(&pbc, width, value) |
57 | #define u(width, ...) u2(width, __VA_ARGS__) |
58 | |
59 | static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, |
60 | char *data, size_t *data_len) |
61 | { |
62 | VAAPIEncodeContext *ctx = avctx->priv_data; |
63 | VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; |
64 | VAAPIEncodeMPEG2Context *priv = ctx->priv_data; |
65 | PutBitContext pbc; |
66 | |
67 | init_put_bits(&pbc, data, 8 * *data_len); |
68 | |
69 | u(32, SEQ_START_CODE, sequence_header_code); |
70 | |
71 | u(12, vseq->picture_width, horizontal_size_value); |
72 | u(12, vseq->picture_height, vertical_size_value); |
73 | u(4, vseq_var(aspect_ratio_information)); |
74 | u(4, 8, frame_rate_code); |
75 | u(18, priv->bit_rate & 0x3fff, bit_rate_value); |
76 | u(1, 1, marker_bit); |
77 | u(10, priv->vbv_buffer_size & 0x3ff, vbv_buffer_size_value); |
78 | u(1, 0, constrained_parameters_flag); |
79 | u(1, 0, load_intra_quantiser_matrix); |
80 | // intra_quantiser_matrix[64] |
81 | u(1, 0, load_non_intra_quantiser_matrix); |
82 | // non_intra_quantiser_matrix[64] |
83 | |
84 | while (put_bits_count(&pbc) % 8) |
85 | u(1, 0, zero_bit); |
86 | |
87 | u(32, EXT_START_CODE, extension_start_code); |
88 | u(4, 1, extension_start_code_identifier); |
89 | u(8, vseqext_field(profile_and_level_indication)); |
90 | u(1, vseqext_field(progressive_sequence)); |
91 | u(2, vseqext_field(chroma_format)); |
92 | u(2, 0, horizontal_size_extension); |
93 | u(2, 0, vertical_size_extension); |
94 | u(12, priv->bit_rate >> 18, bit_rate_extension); |
95 | u(1, 1, marker_bit); |
96 | u(8, priv->vbv_buffer_size >> 10, vbv_buffer_size_extension); |
97 | u(1, vseqext_field(low_delay)); |
98 | u(2, vseqext_field(frame_rate_extension_n)); |
99 | u(2, vseqext_field(frame_rate_extension_d)); |
100 | |
101 | while (put_bits_count(&pbc) % 8) |
102 | u(1, 0, zero_bit); |
103 | |
104 | u(32, GOP_START_CODE, group_start_code); |
105 | u(25, vgop_field(time_code)); |
106 | u(1, vgop_field(closed_gop)); |
107 | u(1, vgop_field(broken_link)); |
108 | |
109 | while (put_bits_count(&pbc) % 8) |
110 | u(1, 0, zero_bit); |
111 | |
112 | *data_len = put_bits_count(&pbc); |
113 | flush_put_bits(&pbc); |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, |
119 | VAAPIEncodePicture *pic, |
120 | char *data, size_t *data_len) |
121 | { |
122 | VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; |
123 | int picture_coding_type; |
124 | PutBitContext pbc; |
125 | |
126 | init_put_bits(&pbc, data, 8 * *data_len); |
127 | |
128 | u(32, PICTURE_START_CODE, picture_start_code); |
129 | u(10, vpic_var(temporal_reference)); |
130 | |
131 | switch (vpic->picture_type) { |
132 | case VAEncPictureTypeIntra: |
133 | picture_coding_type = AV_PICTURE_TYPE_I; |
134 | break; |
135 | case VAEncPictureTypePredictive: |
136 | picture_coding_type = AV_PICTURE_TYPE_P; |
137 | break; |
138 | case VAEncPictureTypeBidirectional: |
139 | picture_coding_type = AV_PICTURE_TYPE_B; |
140 | break; |
141 | default: |
142 | av_assert0(0 && "invalid picture_coding_type"); |
143 | } |
144 | u(3, picture_coding_type, picture_coding_type); |
145 | u(16, 0xffff, vbv_delay); |
146 | if (picture_coding_type == 2 || picture_coding_type == 3) { |
147 | u(1, 0, full_pel_forward_vector); |
148 | u(3, 7, forward_f_code); |
149 | } |
150 | if (picture_coding_type == 3) { |
151 | u(1, 0, full_pel_backward_vector); |
152 | u(3, 7, backward_f_code); |
153 | } |
154 | u(1, 0, extra_bit_picture); |
155 | |
156 | while (put_bits_count(&pbc) % 8) |
157 | u(1, 0, zero_bit); |
158 | |
159 | u(32, EXT_START_CODE, extension_start_code); |
160 | u(4, 8, extension_start_code_identifier); |
161 | u(4, vpic_var(f_code[0][0])); |
162 | u(4, vpic_var(f_code[0][1])); |
163 | u(4, vpic_var(f_code[1][0])); |
164 | u(4, vpic_var(f_code[1][1])); |
165 | u(2, vpcext_field(intra_dc_precision)); |
166 | u(2, vpcext_field(picture_structure)); |
167 | u(1, vpcext_field(top_field_first)); |
168 | u(1, vpcext_field(frame_pred_frame_dct)); |
169 | u(1, vpcext_field(concealment_motion_vectors)); |
170 | u(1, vpcext_field(q_scale_type)); |
171 | u(1, vpcext_field(intra_vlc_format)); |
172 | u(1, vpcext_field(alternate_scan)); |
173 | u(1, vpcext_field(repeat_first_field)); |
174 | u(1, 1, chroma_420_type); |
175 | u(1, vpcext_field(progressive_frame)); |
176 | u(1, vpcext_field(composite_display_flag)); |
177 | if (vpic->picture_coding_extension.bits.composite_display_flag) { |
178 | u(1, vcomp_field(v_axis)); |
179 | u(3, vcomp_field(field_sequence)); |
180 | u(1, vcomp_field(sub_carrier)); |
181 | u(7, vcomp_field(burst_amplitude)); |
182 | u(8, vcomp_field(sub_carrier_phase)); |
183 | } |
184 | |
185 | while (put_bits_count(&pbc) % 8) |
186 | u(1, 0, zero_bit); |
187 | |
188 | *data_len = put_bits_count(&pbc); |
189 | flush_put_bits(&pbc); |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) |
195 | { |
196 | VAAPIEncodeContext *ctx = avctx->priv_data; |
197 | VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; |
198 | VAEncPictureParameterBufferMPEG2 *vpic = ctx->codec_picture_params; |
199 | VAAPIEncodeMPEG2Context *priv = ctx->priv_data; |
200 | |
201 | vseq->intra_period = avctx->gop_size; |
202 | vseq->ip_period = ctx->b_per_p + 1; |
203 | |
204 | vseq->picture_width = avctx->width; |
205 | vseq->picture_height = avctx->height; |
206 | |
207 | vseq->bits_per_second = avctx->bit_rate; |
208 | if (avctx->framerate.num > 0 && avctx->framerate.den > 0) |
209 | vseq->frame_rate = (float)avctx->framerate.num / avctx->framerate.den; |
210 | else |
211 | vseq->frame_rate = (float)avctx->time_base.num / avctx->time_base.den; |
212 | |
213 | vseq->aspect_ratio_information = 1; |
214 | vseq->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); |
215 | |
216 | vseq->sequence_extension.bits.profile_and_level_indication = |
217 | avctx->profile << 4 | avctx->level; |
218 | vseq->sequence_extension.bits.progressive_sequence = 1; |
219 | vseq->sequence_extension.bits.chroma_format = 1; |
220 | vseq->sequence_extension.bits.low_delay = 0; |
221 | vseq->sequence_extension.bits.frame_rate_extension_n = 0; |
222 | vseq->sequence_extension.bits.frame_rate_extension_d = 0; |
223 | |
224 | vseq->new_gop_header = 0; |
225 | vseq->gop_header.bits.time_code = 0; |
226 | vseq->gop_header.bits.closed_gop = 1; |
227 | vseq->gop_header.bits.broken_link = 0; |
228 | |
229 | vpic->forward_reference_picture = VA_INVALID_ID; |
230 | vpic->backward_reference_picture = VA_INVALID_ID; |
231 | vpic->reconstructed_picture = VA_INVALID_ID; |
232 | |
233 | vpic->coded_buf = VA_INVALID_ID; |
234 | |
235 | vpic->temporal_reference = 0; |
236 | vpic->f_code[0][0] = 15; |
237 | vpic->f_code[0][1] = 15; |
238 | vpic->f_code[1][0] = 15; |
239 | vpic->f_code[1][1] = 15; |
240 | |
241 | vpic->picture_coding_extension.bits.intra_dc_precision = 0; |
242 | vpic->picture_coding_extension.bits.picture_structure = 3; |
243 | vpic->picture_coding_extension.bits.top_field_first = 0; |
244 | vpic->picture_coding_extension.bits.frame_pred_frame_dct = 1; |
245 | vpic->picture_coding_extension.bits.concealment_motion_vectors = 0; |
246 | vpic->picture_coding_extension.bits.q_scale_type = 0; |
247 | vpic->picture_coding_extension.bits.intra_vlc_format = 0; |
248 | vpic->picture_coding_extension.bits.alternate_scan = 0; |
249 | vpic->picture_coding_extension.bits.repeat_first_field = 0; |
250 | vpic->picture_coding_extension.bits.progressive_frame = 1; |
251 | vpic->picture_coding_extension.bits.composite_display_flag = 0; |
252 | |
253 | priv->bit_rate = (avctx->bit_rate + 399) / 400; |
254 | priv->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, |
260 | VAAPIEncodePicture *pic) |
261 | { |
262 | VAAPIEncodeContext *ctx = avctx->priv_data; |
263 | VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; |
264 | VAAPIEncodeMPEG2Context *priv = ctx->priv_data; |
265 | int fch, fcv; |
266 | |
267 | switch (avctx->level) { |
268 | case 4: // High. |
269 | case 6: // High 1440. |
270 | fch = 9; |
271 | fcv = 5; |
272 | break; |
273 | case 8: // Main. |
274 | fch = 8; |
275 | fcv = 5; |
276 | break; |
277 | case 10: // Low. |
278 | default: |
279 | fch = 7; |
280 | fcv = 4; |
281 | break; |
282 | } |
283 | |
284 | switch (pic->type) { |
285 | case PICTURE_TYPE_IDR: |
286 | case PICTURE_TYPE_I: |
287 | vpic->picture_type = VAEncPictureTypeIntra; |
288 | priv->last_i_frame = pic->display_order; |
289 | break; |
290 | case PICTURE_TYPE_P: |
291 | vpic->picture_type = VAEncPictureTypePredictive; |
292 | vpic->forward_reference_picture = pic->refs[0]->recon_surface; |
293 | vpic->f_code[0][0] = fch; |
294 | vpic->f_code[0][1] = fcv; |
295 | break; |
296 | case PICTURE_TYPE_B: |
297 | vpic->picture_type = VAEncPictureTypeBidirectional; |
298 | vpic->forward_reference_picture = pic->refs[0]->recon_surface; |
299 | vpic->backward_reference_picture = pic->refs[1]->recon_surface; |
300 | vpic->f_code[0][0] = fch; |
301 | vpic->f_code[0][1] = fcv; |
302 | vpic->f_code[1][0] = fch; |
303 | vpic->f_code[1][1] = fcv; |
304 | break; |
305 | default: |
306 | av_assert0(0 && "invalid picture type"); |
307 | } |
308 | |
309 | vpic->reconstructed_picture = pic->recon_surface; |
310 | vpic->coded_buf = pic->output_buffer; |
311 | |
312 | vpic->temporal_reference = pic->display_order - priv->last_i_frame; |
313 | |
314 | pic->nb_slices = priv->mb_height; |
315 | |
316 | return 0; |
317 | } |
318 | |
319 | static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, |
320 | VAAPIEncodePicture *pic, |
321 | VAAPIEncodeSlice *slice) |
322 | { |
323 | VAAPIEncodeContext *ctx = avctx->priv_data; |
324 | VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; |
325 | VAAPIEncodeMPEG2Context *priv = ctx->priv_data; |
326 | int qp; |
327 | |
328 | vslice->macroblock_address = priv->mb_width * slice->index; |
329 | vslice->num_macroblocks = priv->mb_width; |
330 | |
331 | switch (pic->type) { |
332 | case PICTURE_TYPE_IDR: |
333 | case PICTURE_TYPE_I: |
334 | qp = priv->quant_i; |
335 | break; |
336 | case PICTURE_TYPE_P: |
337 | qp = priv->quant_p; |
338 | break; |
339 | case PICTURE_TYPE_B: |
340 | qp = priv->quant_b; |
341 | break; |
342 | default: |
343 | av_assert0(0 && "invalid picture type"); |
344 | } |
345 | |
346 | vslice->quantiser_scale_code = qp; |
347 | vslice->is_intra_slice = (pic->type == PICTURE_TYPE_IDR || |
348 | pic->type == PICTURE_TYPE_I); |
349 | |
350 | return 0; |
351 | } |
352 | |
353 | static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) |
354 | { |
355 | VAAPIEncodeContext *ctx = avctx->priv_data; |
356 | VAAPIEncodeMPEG2Context *priv = ctx->priv_data; |
357 | |
358 | priv->mb_width = FFALIGN(avctx->width, 16) / 16; |
359 | priv->mb_height = FFALIGN(avctx->height, 16) / 16; |
360 | |
361 | if (ctx->va_rc_mode == VA_RC_CQP) { |
362 | priv->quant_p = av_clip(avctx->global_quality, 1, 31); |
363 | if (avctx->i_quant_factor > 0.0) |
364 | priv->quant_i = av_clip((avctx->global_quality * |
365 | avctx->i_quant_factor + |
366 | avctx->i_quant_offset) + 0.5, |
367 | 1, 31); |
368 | else |
369 | priv->quant_i = priv->quant_p; |
370 | if (avctx->b_quant_factor > 0.0) |
371 | priv->quant_b = av_clip((avctx->global_quality * |
372 | avctx->b_quant_factor + |
373 | avctx->b_quant_offset) + 0.5, |
374 | 1, 31); |
375 | else |
376 | priv->quant_b = priv->quant_p; |
377 | |
378 | av_log(avctx, AV_LOG_DEBUG, "Using fixed quantiser " |
379 | "%d / %d / %d for I- / P- / B-frames.\n", |
380 | priv->quant_i, priv->quant_p, priv->quant_b); |
381 | |
382 | } else { |
383 | av_assert0(0 && "Invalid RC mode."); |
384 | } |
385 | |
386 | return 0; |
387 | } |
388 | |
389 | static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { |
390 | .priv_data_size = sizeof(VAAPIEncodeMPEG2Context), |
391 | |
392 | .configure = &vaapi_encode_mpeg2_configure, |
393 | |
394 | .sequence_params_size = sizeof(VAEncSequenceParameterBufferMPEG2), |
395 | .init_sequence_params = &vaapi_encode_mpeg2_init_sequence_params, |
396 | |
397 | .picture_params_size = sizeof(VAEncPictureParameterBufferMPEG2), |
398 | .init_picture_params = &vaapi_encode_mpeg2_init_picture_params, |
399 | |
400 | .slice_params_size = sizeof(VAEncSliceParameterBufferMPEG2), |
401 | .init_slice_params = &vaapi_encode_mpeg2_init_slice_params, |
402 | |
403 | .sequence_header_type = VAEncPackedHeaderSequence, |
404 | .write_sequence_header = &vaapi_encode_mpeg2_write_sequence_header, |
405 | |
406 | .picture_header_type = VAEncPackedHeaderPicture, |
407 | .write_picture_header = &vaapi_encode_mpeg2_write_picture_header, |
408 | }; |
409 | |
410 | static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) |
411 | { |
412 | VAAPIEncodeContext *ctx = avctx->priv_data; |
413 | |
414 | ctx->codec = &vaapi_encode_type_mpeg2; |
415 | |
416 | switch (avctx->profile) { |
417 | case FF_PROFILE_MPEG2_SIMPLE: |
418 | ctx->va_profile = VAProfileMPEG2Simple; |
419 | break; |
420 | case FF_PROFILE_MPEG2_MAIN: |
421 | ctx->va_profile = VAProfileMPEG2Main; |
422 | break; |
423 | default: |
424 | av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n", |
425 | avctx->profile); |
426 | return AVERROR(EINVAL); |
427 | } |
428 | |
429 | ctx->va_entrypoint = VAEntrypointEncSlice; |
430 | ctx->va_rt_format = VA_RT_FORMAT_YUV420; |
431 | ctx->va_rc_mode = VA_RC_CQP; |
432 | |
433 | ctx->va_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | |
434 | VA_ENC_PACKED_HEADER_PICTURE; |
435 | |
436 | ctx->surface_width = FFALIGN(avctx->width, 16); |
437 | ctx->surface_height = FFALIGN(avctx->height, 16); |
438 | |
439 | return ff_vaapi_encode_init(avctx); |
440 | } |
441 | |
442 | static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { |
443 | { "profile", "4" }, |
444 | { "level", "4" }, |
445 | { "bf", "1" }, |
446 | { "g", "120" }, |
447 | { "i_qfactor", "1" }, |
448 | { "i_qoffset", "0" }, |
449 | { "b_qfactor", "6/5" }, |
450 | { "b_qoffset", "0" }, |
451 | { "global_quality", "10" }, |
452 | { NULL }, |
453 | }; |
454 | |
455 | AVCodec ff_mpeg2_vaapi_encoder = { |
456 | .name = "mpeg2_vaapi", |
457 | .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 (VAAPI)"), |
458 | .type = AVMEDIA_TYPE_VIDEO, |
459 | .id = AV_CODEC_ID_MPEG2VIDEO, |
460 | .priv_data_size = sizeof(VAAPIEncodeContext), |
461 | .init = &vaapi_encode_mpeg2_init, |
462 | .encode2 = &ff_vaapi_encode2, |
463 | .close = &ff_vaapi_encode_close, |
464 | .capabilities = AV_CODEC_CAP_DELAY, |
465 | .defaults = vaapi_encode_mpeg2_defaults, |
466 | .pix_fmts = (const enum AVPixelFormat[]) { |
467 | AV_PIX_FMT_VAAPI, |
468 | AV_PIX_FMT_NONE, |
469 | }, |
470 | }; |
471 |