2 * Copyright (C) 2021 Intel Corporation
3 * Author: He Junyan <junyan.he@intel.com>
4 * Author: Víctor Jáquez <vjaquez@igalia.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:element-vah264enc
25 * @short_description: A VA-API based H264 video encoder
27 * vah264enc encodes raw video VA surfaces into H.264 bitstreams using
28 * the installed and chosen [VA-API](https://01.org/linuxmedia/vaapi)
31 * The raw video frames in main memory can be imported into VA surfaces.
33 * ## Example launch line
35 * gst-launch-1.0 videotestsrc num-buffers=60 ! timeoverlay ! vah264enc ! h264parse ! mp4mux ! filesink location=test.mp4
43 * 1. Look ahead, which can optimize the slice type and QP.
45 * 3. The stereo encoding such as the frame-packing or MVC.
46 * 4. Weight prediction of B frame.
54 #include "gstvah264enc.h"
56 #include <gst/codecparsers/gsth264bitwriter.h>
57 #include <gst/va/gstva.h>
58 #include <gst/video/video.h>
59 #include <va/va_drmcommon.h>
62 #include "gstvaencoder.h"
63 #include "gstvacaps.h"
64 #include "gstvaprofile.h"
65 #include "gstvadisplay_priv.h"
67 GST_DEBUG_CATEGORY_STATIC (gst_va_h264enc_debug);
68 #ifndef GST_DISABLE_GST_DEBUG
69 #define GST_CAT_DEFAULT gst_va_h264enc_debug
71 #define GST_CAT_DEFAULT NULL
74 typedef struct _GstVaH264Enc GstVaH264Enc;
75 typedef struct _GstVaH264EncClass GstVaH264EncClass;
76 typedef struct _GstVaH264EncFrame GstVaH264EncFrame;
77 typedef struct _GstVaH264LevelLimits GstVaH264LevelLimits;
79 #define GST_VA_H264_ENC(obj) ((GstVaH264Enc *) obj)
80 #define GST_VA_H264_ENC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaH264EncClass))
81 #define GST_VA_H264_ENC_CLASS(klass) ((GstVaH264EncClass *) klass)
101 PROP_TARGET_PERCENTAGE,
110 static GParamSpec *properties[N_PROPERTIES];
112 /* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
114 /* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
115 #define SX_CPB_SIZE 4
116 /* Maximum sizes for common headers (in bits) */
117 #define MAX_SPS_HDR_SIZE 16473
118 #define MAX_VUI_PARAMS_SIZE 210
119 #define MAX_HRD_PARAMS_SIZE 4103
120 #define MAX_PPS_HDR_SIZE 101
121 #define MAX_SLICE_HDR_SIZE 397 + 2572 + 6670 + 2402
123 #define MAX_GOP_SIZE 1024
125 static GstObjectClass *parent_class = NULL;
128 struct _GstVaH264EncClass
130 GstVideoEncoderClass parent_class;
133 gchar *render_device_path;
135 gboolean (*reconfig) (GstVaH264Enc * encoder);
136 gboolean (*push_frame) (GstVaH264Enc * encoder,
137 GstVideoCodecFrame * frame,
139 gboolean (*pop_frame) (GstVaH264Enc * encoder,
140 GstVideoCodecFrame ** out_frame);
141 gboolean (*encode_frame) (GstVaH264Enc * encoder,
142 GstVideoCodecFrame * frame);
149 GstVideoEncoder parent_instance;
151 GstVaDisplay *display;
156 VAEntrypoint entrypoint;
167 guint32 num_ref_frames;
178 gboolean use_trellis;
183 guint32 target_percentage;
184 guint32 target_usage;
187 GstVideoCodecState *input_state;
188 GstVideoCodecState *output_state;
190 GstVideoInfo in_info;
191 GstVideoInfo sinkpad_info;
192 GstBufferPool *raw_pool;
194 GstClockTime start_pts;
195 GstClockTime frame_duration;
196 /* Total frames we handled since reconfig. */
197 guint input_frame_count;
198 guint output_frame_count;
200 GstVaEncoder *encoder;
211 const gchar *level_str;
212 /* Minimum Compression Ratio (A.3.1) */
216 gboolean use_trellis;
218 guint32 packed_headers;
222 /* frames between two IDR [idr, ...., idr) */
224 /* How may IDRs we have encoded */
225 guint32 total_idr_count;
226 /* frames between I/P and P frames [I, B, B, .., B, P) */
228 /* frames between I frames [I, B, B, .., B, P, ..., I), open GOP */
230 /* B frames between I/P and P. */
232 /* Use B pyramid structure in the GOP. */
234 /* Level 0 is the simple B not acting as ref. */
235 guint32 highest_pyramid_level;
236 /* If open GOP, I frames within a GOP. */
238 /* A map of all frames types within a GOP. */
243 guint8 pyramid_level;
244 /* Only for b pyramid */
245 gint left_ref_poc_diff;
246 gint right_ref_poc_diff;
247 } frame_types[MAX_GOP_SIZE];
248 /* current index in the frames types map. */
249 guint cur_frame_index;
250 /* Number of ref frames within current GOP. H264's frame num. */
252 /* Max frame num within a GOP. */
253 guint32 max_frame_num;
254 guint32 log2_max_frame_num;
255 /* Max poc within a GOP. */
256 guint32 max_pic_order_cnt;
257 guint32 log2_max_pic_order_cnt;
259 /* Total ref frames of list0 and list1. */
260 guint32 num_ref_frames;
261 guint32 ref_num_list0;
262 guint32 ref_num_list1;
264 guint num_reorder_frames;
270 guint32 rc_ctrl_mode;
277 /* macroblock bitrate control */
279 guint target_bitrate;
280 guint target_percentage;
283 guint max_bitrate_bits;
284 guint target_bitrate_bits;
285 /* length of CPB buffer */
287 /* length of CPB buffer (bits) */
288 guint cpb_length_bits;
291 GstH264SPS sequence_hdr;
294 struct _GstVaH264EncFrame
296 GstVaEncodePicture *picture;
297 GstH264SliceType type;
300 /* Only for b pyramid */
301 gint left_ref_poc_diff;
302 gint right_ref_poc_diff;
307 /* The pic_num will be marked as unused_for_reference, which is
308 * replaced by this frame. -1 if we do not need to care about it
310 gint unused_for_reference_pic_num;
312 /* The total frame count we handled. */
313 guint total_frame_count;
317 * GstVaH264LevelLimits:
318 * @name: the level name
319 * @level_idc: the H.264 level_idc value
320 * @MaxMBPS: the maximum macroblock processing rate (MB/sec)
321 * @MaxFS: the maximum frame size (MBs)
322 * @MaxDpbMbs: the maxium decoded picture buffer size (MBs)
323 * @MaxBR: the maximum video bit rate (kbps)
324 * @MaxCPB: the maximum CPB size (kbits)
325 * @MinCR: the minimum Compression Ratio
327 * The data structure that describes the limits of an H.264 level.
329 struct _GstVaH264LevelLimits
341 /* Table A-1 - Level limits */
343 static const GstVaH264LevelLimits _va_h264_level_limits[] = {
344 /* level idc MaxMBPS MaxFS MaxDpbMbs MaxBR MaxCPB MinCr */
345 { "1", 10, 1485, 99, 396, 64, 175, 2 },
346 { "1b", 11, 1485, 99, 396, 128, 350, 2 },
347 { "1.1", 11, 3000, 396, 900, 192, 500, 2 },
348 { "1.2", 12, 6000, 396, 2376, 384, 1000, 2 },
349 { "1.3", 13, 11880, 396, 2376, 768, 2000, 2 },
350 { "2", 20, 11880, 396, 2376, 2000, 2000, 2 },
351 { "2.1", 21, 19800, 792, 4752, 4000, 4000, 2 },
352 { "2.2", 22, 20250, 1620, 8100, 4000, 4000, 2 },
353 { "3", 30, 40500, 1620, 8100, 10000, 10000, 2 },
354 { "3.1", 31, 108000, 3600, 18000, 14000, 14000, 4 },
355 { "3.2", 32, 216000, 5120, 20480, 20000, 20000, 4 },
356 { "4", 40, 245760, 8192, 32768, 20000, 25000, 4 },
357 { "4.1", 41, 245760, 8192, 32768, 50000, 62500, 2 },
358 { "4.2", 42, 522240, 8704, 34816, 50000, 62500, 2 },
359 { "5", 50, 589824, 22080, 110400, 135000, 135000, 2 },
360 { "5.1", 51, 983040, 36864, 184320, 240000, 240000, 2 },
361 { "5.2", 52, 2073600, 36864, 184320, 240000, 240000, 2 },
362 { "6", 60, 4177920, 139264, 696320, 240000, 240000, 2 },
363 { "6.1", 61, 8355840, 139264, 696320, 480000, 480000, 2 },
364 { "6.2", 62, 16711680, 139264, 696320, 800000, 800000, 2 },
369 _slice_type_name (GstH264SliceType type)
372 case GST_H264_P_SLICE:
374 case GST_H264_B_SLICE:
376 case GST_H264_I_SLICE:
379 g_assert_not_reached ();
386 _rate_control_get_name (guint32 rc_mode)
401 g_assert_not_reached ();
411 gst_va_h264_enc_mbbrc_get_type (void)
413 static gsize type = 0;
415 static const GEnumValue values[] = {
416 {0, "Auto choose", "auto"},
417 {1, "Always enable", "enable"},
418 {2, "Always disable", "disable"},
422 if (g_once_init_enter (&type)) {
425 _type = g_enum_register_static ("GstVaH264Mbbrc", values);
426 g_once_init_leave (&type, _type);
432 static GstVaH264EncFrame *
433 gst_va_enc_frame_new (void)
435 GstVaH264EncFrame *frame;
437 frame = g_slice_new (GstVaH264EncFrame);
438 frame->last_frame = FALSE;
439 frame->frame_num = 0;
440 frame->unused_for_reference_pic_num = -1;
441 frame->picture = NULL;
442 frame->total_frame_count = 0;
448 gst_va_enc_frame_free (gpointer pframe)
450 GstVaH264EncFrame *frame = pframe;
451 g_clear_pointer (&frame->picture, gst_va_encode_picture_free);
452 g_slice_free (GstVaH264EncFrame, frame);
455 static inline GstVaH264EncFrame *
456 _enc_frame (GstVideoCodecFrame * frame)
458 GstVaH264EncFrame *enc_frame = gst_video_codec_frame_get_user_data (frame);
459 g_assert (enc_frame);
463 /* Normalizes bitrate (and CPB size) for HRD conformance */
465 _calculate_bitrate_hrd (GstVaH264Enc * self)
467 guint bitrate_bits, cpb_bits_size;
469 /* Round down bitrate. This is a hard limit mandated by the user */
470 g_assert (SX_BITRATE >= 6);
471 bitrate_bits = (self->rc.max_bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
472 GST_DEBUG_OBJECT (self, "Max bitrate: %u bits/sec", bitrate_bits);
473 self->rc.max_bitrate_bits = bitrate_bits;
475 bitrate_bits = (self->rc.target_bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
476 GST_DEBUG_OBJECT (self, "Target bitrate: %u bits/sec", bitrate_bits);
477 self->rc.target_bitrate_bits = bitrate_bits;
479 if (self->rc.cpb_size > 0 && self->rc.cpb_size < (self->rc.max_bitrate / 2)) {
480 GST_INFO_OBJECT (self, "Too small cpb_size: %d", self->rc.cpb_size);
481 self->rc.cpb_size = 0;
484 if (self->rc.cpb_size == 0) {
485 /* We cache 2 second coded data by default. */
486 self->rc.cpb_size = self->rc.max_bitrate * 2;
487 GST_INFO_OBJECT (self, "Adjust cpb_size to: %d", self->rc.cpb_size);
490 /* Round up CPB size. This is an HRD compliance detail */
491 g_assert (SX_CPB_SIZE >= 4);
492 cpb_bits_size = (self->rc.cpb_size * 1000) & ~((1U << SX_CPB_SIZE) - 1);
494 GST_DEBUG_OBJECT (self, "HRD CPB size: %u bits", cpb_bits_size);
495 self->rc.cpb_length_bits = cpb_bits_size;
498 /* Estimates a good enough bitrate if none was supplied */
500 _ensure_rate_control (GstVaH264Enc * self)
502 /* User can specify the properties of: "bitrate", "target-percentage",
503 * "max-qp", "min-qp", "qpi", "qpp", "qpb", "mbbrc", "cpb-size",
504 * "rate-control" and "target-usage" to control the RC behavior.
506 * "target-usage" is different from the others, it controls the encoding
507 * speed and quality, while the others control encoding bit rate and
508 * quality. The lower value has better quality(maybe bigger MV search
509 * range) but slower speed, the higher value has faster speed but lower
512 * The possible composition to control the bit rate and quality:
514 * 1. CQP mode: "rate-control=cqp", then "qpi", "qpp" and "qpb"
515 * specify the QP of I/P/B frames respectively(within the
516 * "max-qp" and "min-qp" range). The QP will not change during
517 * the whole stream. Other properties are ignored.
519 * 2. CBR mode: "rate-control=CBR", then the "bitrate" specify the
520 * target bit rate and the "cpb-size" specifies the max coded
521 * picture buffer size to avoid overflow. If the "bitrate" is not
522 * set, it is calculated by the picture resolution and frame
523 * rate. If "cpb-size" is not set, it is set to the size of
524 * caching 2 second coded data. Encoder will try its best to make
525 * the QP with in the ["max-qp", "min-qp"] range. "mbbrc" can
526 * enable bit rate control in macro block level. Other paramters
529 * 3. VBR mode: "rate-control=VBR", then the "bitrate" specify the
530 * target bit rate, "target-percentage" is used to calculate the
531 * max bit rate of VBR mode by ("bitrate" * 100) /
532 * "target-percentage". It is also used by driver to calculate
533 * the min bit rate. The "cpb-size" specifies the max coded
534 * picture buffer size to avoid overflow. If the "bitrate" is not
535 * set, the target bit rate will be calculated by the picture
536 * resolution and frame rate. Encoder will try its best to make
537 * the QP with in the ["max-qp", "min-qp"] range. "mbbrc" can
538 * enable bit rate control in macro block level. Other paramters
541 * 4. VCM mode: "rate-control=VCM", then the "bitrate" specify the
542 * target bit rate, and encoder will try its best to make the QP
543 * with in the ["max-qp", "min-qp"] range. Other paramters are
549 guint32 quality_level;
551 quality_level = gst_va_encoder_get_quality_level (self->encoder,
552 self->profile, self->entrypoint);
553 if (self->rc.target_usage > quality_level) {
554 GST_INFO_OBJECT (self, "User setting target-usage: %d is not supported, "
555 "fallback to %d", self->rc.target_usage, quality_level);
556 self->rc.target_usage = quality_level;
558 self->prop.target_usage = self->rc.target_usage;
559 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET_USAGE]);
562 /* TODO: find a better heuristics to infer a nearer control mode */
563 rc_mode = gst_va_encoder_get_rate_control_mode (self->encoder,
564 self->profile, self->entrypoint);
565 if (!(rc_mode & self->prop.rc_ctrl)) {
566 GST_INFO_OBJECT (self, "The race control mode %s is not supported, "
567 "fallback to %s mode",
568 _rate_control_get_name (self->prop.rc_ctrl),
569 _rate_control_get_name (VA_RC_CQP));
570 self->rc.rc_ctrl_mode = VA_RC_CQP;
572 self->prop.rc_ctrl = self->rc.rc_ctrl_mode;
573 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RATE_CONTROL]);
576 if (self->rc.min_qp > self->rc.max_qp) {
577 GST_INFO_OBJECT (self, "The min_qp %d is bigger than the max_qp %d, "
578 "set it to the max_qp", self->rc.min_qp, self->rc.max_qp);
579 self->rc.min_qp = self->rc.max_qp;
581 self->prop.min_qp = self->rc.min_qp;
582 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_QP]);
585 /* Make all the qp in the valid range */
586 if (self->rc.qp_i < self->rc.min_qp) {
587 if (self->rc.qp_i != 26)
588 GST_INFO_OBJECT (self, "The qp_i %d is smaller than the min_qp %d, "
589 "set it to the min_qp", self->rc.qp_i, self->rc.min_qp);
590 self->rc.qp_i = self->rc.min_qp;
592 if (self->rc.qp_i > self->rc.max_qp) {
593 if (self->rc.qp_i != 26)
594 GST_INFO_OBJECT (self, "The qp_i %d is bigger than the max_qp %d, "
595 "set it to the max_qp", self->rc.qp_i, self->rc.max_qp);
596 self->rc.qp_i = self->rc.max_qp;
599 if (self->rc.qp_p < self->rc.min_qp) {
600 if (self->rc.qp_p != 26)
601 GST_INFO_OBJECT (self, "The qp_p %d is smaller than the min_qp %d, "
602 "set it to the min_qp", self->rc.qp_p, self->rc.min_qp);
603 self->rc.qp_p = self->rc.min_qp;
605 if (self->rc.qp_p > self->rc.max_qp) {
606 if (self->rc.qp_p != 26)
607 GST_INFO_OBJECT (self, "The qp_p %d is bigger than the max_qp %d, "
608 "set it to the max_qp", self->rc.qp_p, self->rc.max_qp);
609 self->rc.qp_p = self->rc.max_qp;
612 if (self->rc.qp_b < self->rc.min_qp) {
613 if (self->rc.qp_b != 26)
614 GST_INFO_OBJECT (self, "The qp_b %d is smaller than the min_qp %d, "
615 "set it to the min_qp", self->rc.qp_b, self->rc.min_qp);
616 self->rc.qp_b = self->rc.min_qp;
618 if (self->rc.qp_b > self->rc.max_qp) {
619 if (self->rc.qp_b != 26)
620 GST_INFO_OBJECT (self, "The qp_b %d is bigger than the max_qp %d, "
621 "set it to the max_qp", self->rc.qp_b, self->rc.max_qp);
622 self->rc.qp_b = self->rc.max_qp;
625 bitrate = self->prop.bitrate;
626 /* Calculate a bitrate is not set. */
627 if ((self->rc.rc_ctrl_mode == VA_RC_CBR || self->rc.rc_ctrl_mode == VA_RC_VBR
628 || self->rc.rc_ctrl_mode == VA_RC_VCM) && bitrate == 0) {
629 /* Default compression: 48 bits per macroblock in "high-compression" mode */
630 guint bits_per_mb = 48;
633 /* According to the literature and testing, CABAC entropy coding
634 * mode could provide for +10% to +18% improvement in general,
635 * thus estimating +15% here ; and using adaptive 8x8 transforms
636 * in I-frames could bring up to +10% improvement. */
637 if (!self->use_cabac)
638 bits_per_mb += (bits_per_mb * 15) / 100;
639 if (!self->use_dct8x8)
640 bits_per_mb += (bits_per_mb * 10) / 100;
642 factor = (guint64) self->mb_width * self->mb_height * bits_per_mb;
643 bitrate = gst_util_uint64_scale (factor,
644 GST_VIDEO_INFO_FPS_N (&self->in_info),
645 GST_VIDEO_INFO_FPS_D (&self->in_info)) / 1000;
646 GST_INFO_OBJECT (self, "target bitrate computed to %u kbps", bitrate);
649 /* Adjust the setting based on RC mode. */
650 switch (self->rc.rc_ctrl_mode) {
652 self->rc.max_bitrate = 0;
653 self->rc.target_bitrate = 0;
654 self->rc.target_percentage = 0;
655 self->rc.cpb_size = 0;
658 self->rc.max_bitrate = bitrate;
659 self->rc.target_bitrate = bitrate;
660 self->rc.target_percentage = 100;
661 self->rc.qp_i = self->rc.qp_p = self->rc.qp_b = 26;
664 g_assert (self->rc.target_percentage >= 10);
665 self->rc.max_bitrate = (guint) gst_util_uint64_scale_int (bitrate,
666 100, self->rc.target_percentage);
667 self->rc.target_bitrate = bitrate;
668 self->rc.qp_i = self->rc.qp_p = self->rc.qp_b = 26;
671 self->rc.max_bitrate = bitrate;
672 self->rc.target_bitrate = bitrate;
673 self->rc.target_percentage = 0;
674 self->rc.qp_i = self->rc.qp_p = self->rc.qp_b = 26;
675 self->rc.cpb_size = 0;
677 if (self->gop.num_bframes > 0) {
678 GST_INFO_OBJECT (self, "VCM mode just support I/P mode, no B frame");
679 self->gop.num_bframes = 0;
680 self->gop.b_pyramid = FALSE;
685 if (self->rc.rc_ctrl_mode != VA_RC_CQP)
686 _calculate_bitrate_hrd (self);
689 if (self->rc.cpb_size != self->prop.cpb_size) {
690 self->prop.cpb_size = self->rc.cpb_size;
691 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CPB_SIZE]);
694 if (self->prop.target_percentage != self->rc.target_percentage) {
695 self->prop.target_percentage = self->rc.target_percentage;
696 g_object_notify_by_pspec (G_OBJECT (self),
697 properties[PROP_TARGET_PERCENTAGE]);
700 if (self->prop.qp_i != self->rc.qp_i) {
701 self->prop.qp_i = self->rc.qp_i;
702 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_I]);
704 if (self->prop.qp_p != self->rc.qp_p) {
705 self->prop.qp_p = self->rc.qp_p;
706 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_P]);
708 if (self->prop.qp_b != self->rc.qp_b) {
709 self->prop.qp_b = self->rc.qp_b;
710 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_QP_B]);
715 _get_h264_cpb_nal_factor (VAProfile profile)
721 case VAProfileH264High:
724 case VAProfileH264ConstrainedBaseline:
725 case VAProfileH264Main:
728 case VAProfileH264MultiviewHigh:
729 case VAProfileH264StereoHigh:
730 f = 1500; /* H.10.2.1 (r) */
733 g_assert_not_reached ();
740 /* Derives the level from the currently set limits */
742 _calculate_level (GstVaH264Enc * self)
744 const guint cpb_factor = _get_h264_cpb_nal_factor (self->profile);
745 guint i, PicSizeMbs, MaxDpbMbs, MaxMBPS;
747 PicSizeMbs = self->mb_width * self->mb_height;
748 MaxDpbMbs = PicSizeMbs * (self->gop.num_ref_frames + 1);
749 MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
750 GST_VIDEO_INFO_FPS_N (&self->in_info),
751 GST_VIDEO_INFO_FPS_D (&self->in_info));
753 for (i = 0; i < G_N_ELEMENTS (_va_h264_level_limits); i++) {
754 const GstVaH264LevelLimits *const limits = &_va_h264_level_limits[i];
755 if (PicSizeMbs <= limits->MaxFS && MaxDpbMbs <= limits->MaxDpbMbs
756 && MaxMBPS <= limits->MaxMBPS && (!self->rc.max_bitrate_bits
757 || self->rc.max_bitrate_bits <= (limits->MaxBR * 1000 * cpb_factor))
758 && (!self->rc.cpb_length_bits
759 || self->rc.cpb_length_bits <=
760 (limits->MaxCPB * 1000 * cpb_factor))) {
762 self->level_idc = _va_h264_level_limits[i].level_idc;
763 self->level_str = _va_h264_level_limits[i].name;
764 self->min_cr = _va_h264_level_limits[i].MinCR;
770 GST_ERROR_OBJECT (self,
771 "failed to find a suitable level matching codec config");
776 _validate_parameters (GstVaH264Enc * self)
780 /* Ensure the num_slices provided by the user not exceed the limit
781 * of the number of slices permitted by the stream and by the
783 g_assert (self->num_slices >= 1);
784 max_slices = gst_va_encoder_get_max_slice_num (self->encoder,
785 self->profile, self->entrypoint);
786 if (self->num_slices > max_slices)
787 self->num_slices = max_slices;
788 /* The stream size limit. */
789 if (self->num_slices > ((self->mb_width * self->mb_height + 1) / 2))
790 self->num_slices = ((self->mb_width * self->mb_height + 1) / 2);
792 if (self->prop.num_slices != self->num_slices) {
793 self->prop.num_slices = self->num_slices;
794 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NUM_SLICES]);
797 /* Ensure trellis. */
798 if (self->use_trellis &&
799 !gst_va_encoder_has_trellis (self->encoder, self->profile,
801 GST_INFO_OBJECT (self, "The trellis is not supported");
802 self->use_trellis = FALSE;
805 if (self->prop.use_trellis != self->use_trellis) {
806 self->prop.use_trellis = self->use_trellis;
807 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRELLIS]);
811 /* Get log2_max_frame_num_minus4, log2_max_pic_order_cnt_lsb_minus4
812 * value, shall be in the range of 0 to 12, inclusive. */
814 _get_log2_max_num (guint num)
823 /* shall be in the range of 0+4 to 12+4, inclusive. */
826 } else if (ret > 16) {
833 _print_gop_structure (GstVaH264Enc * self)
835 #ifndef GST_DISABLE_GST_DEBUG
839 if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) < GST_LEVEL_INFO)
842 str = g_string_new (NULL);
844 g_string_append_printf (str, "[ ");
846 for (i = 0; i < self->gop.idr_period; i++) {
848 g_string_append_printf (str, "IDR");
851 g_string_append_printf (str, ", ");
854 g_string_append_printf (str, "%s",
855 _slice_type_name (self->gop.frame_types[i].slice_type));
857 if (self->gop.b_pyramid
858 && self->gop.frame_types[i].slice_type == GST_H264_B_SLICE) {
859 g_string_append_printf (str, "<L%d (%d, %d)>",
860 self->gop.frame_types[i].pyramid_level,
861 self->gop.frame_types[i].left_ref_poc_diff,
862 self->gop.frame_types[i].right_ref_poc_diff);
865 if (self->gop.frame_types[i].is_ref) {
866 g_string_append_printf (str, "(ref)");
871 g_string_append_printf (str, " ]");
873 GST_INFO_OBJECT (self, "GOP size: %d, forward reference %d, backward"
874 " reference %d, GOP structure: %s", self->gop.idr_period,
875 self->gop.ref_num_list0, self->gop.ref_num_list1, str->str);
877 g_string_free (str, TRUE);
884 gint left_ref_poc_diff;
885 gint right_ref_poc_diff;
889 _set_pyramid_info (struct PyramidInfo *info, guint len,
890 guint current_level, guint highest_level)
896 if (current_level == highest_level || len == 1) {
897 for (index = 0; index < len; index++) {
898 info[index].level = current_level;
899 info[index].left_ref_poc_diff = (index + 1) * -2;
900 info[index].right_ref_poc_diff = (len - index) * 2;
907 info[index].level = current_level;
908 info[index].left_ref_poc_diff = (index + 1) * -2;
909 info[index].right_ref_poc_diff = (len - index) * 2;
914 _set_pyramid_info (info, index, current_level, highest_level);
917 _set_pyramid_info (&info[index + 1], len - (index + 1),
918 current_level, highest_level);
922 _create_gop_frame_types (GstVaH264Enc * self)
925 guint i_frames = self->gop.num_iframes;
926 struct PyramidInfo pyramid_info[31] = { 0, };
928 if (self->gop.highest_pyramid_level > 0) {
929 g_assert (self->gop.num_bframes > 0);
930 _set_pyramid_info (pyramid_info, self->gop.num_bframes,
931 0, self->gop.highest_pyramid_level);
934 g_assert (self->gop.idr_period <= MAX_GOP_SIZE);
935 for (i = 0; i < self->gop.idr_period; i++) {
937 self->gop.frame_types[i].slice_type = GST_H264_I_SLICE;
938 self->gop.frame_types[i].is_ref = TRUE;
942 /* Intra only stream. */
943 if (self->gop.ip_period == 0) {
944 self->gop.frame_types[i].slice_type = GST_H264_I_SLICE;
945 self->gop.frame_types[i].is_ref = FALSE;
949 if (i % self->gop.ip_period) {
950 guint pyramid_index =
951 i % self->gop.ip_period - 1 /* The first P or IDR */ ;
953 self->gop.frame_types[i].slice_type = GST_H264_B_SLICE;
954 self->gop.frame_types[i].pyramid_level =
955 pyramid_info[pyramid_index].level;
956 self->gop.frame_types[i].is_ref =
957 (self->gop.frame_types[i].pyramid_level <
958 self->gop.highest_pyramid_level);
959 self->gop.frame_types[i].left_ref_poc_diff =
960 pyramid_info[pyramid_index].left_ref_poc_diff;
961 self->gop.frame_types[i].right_ref_poc_diff =
962 pyramid_info[pyramid_index].right_ref_poc_diff;
966 if (self->gop.i_period && i % self->gop.i_period == 0 && i_frames > 0) {
967 /* Replace P with I. */
968 self->gop.frame_types[i].slice_type = GST_H264_I_SLICE;
969 self->gop.frame_types[i].is_ref = TRUE;
974 self->gop.frame_types[i].slice_type = GST_H264_P_SLICE;
975 self->gop.frame_types[i].is_ref = TRUE;
978 /* Force the last one to be a P */
979 if (self->gop.idr_period > 1 && self->gop.ip_period > 0) {
980 self->gop.frame_types[self->gop.idr_period - 1].slice_type =
982 self->gop.frame_types[self->gop.idr_period - 1].is_ref = TRUE;
986 /* Consider the idr_period, num_bframes, L0/L1 reference number.
987 * TODO: Load some preset fixed GOP structure.
988 * TODO: Skip this if in lookahead mode. */
990 _generate_gop_structure (GstVaH264Enc * self)
992 guint32 list0, list1, gop_ref_num;
995 /* If not set, generate a idr every second */
996 if (self->gop.idr_period == 0) {
997 self->gop.idr_period = (GST_VIDEO_INFO_FPS_N (&self->in_info)
998 + GST_VIDEO_INFO_FPS_D (&self->in_info) - 1) /
999 GST_VIDEO_INFO_FPS_D (&self->in_info);
1002 /* Do not use a too huge GOP size. */
1003 if (self->gop.idr_period > 1024) {
1004 self->gop.idr_period = 1024;
1005 GST_INFO_OBJECT (self, "Lowering the GOP size to %d", self->gop.idr_period);
1008 if (self->gop.idr_period != self->prop.key_int_max) {
1009 self->prop.key_int_max = self->gop.idr_period;
1010 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEY_INT_MAX]);
1013 /* Prefer have more than 1 refs for the GOP which is not very small. */
1014 if (self->gop.idr_period > 8) {
1015 if (self->gop.num_bframes > (self->gop.idr_period - 1) / 2) {
1016 self->gop.num_bframes = (self->gop.idr_period - 1) / 2;
1017 GST_INFO_OBJECT (self, "Lowering the number of num_bframes to %d",
1018 self->gop.num_bframes);
1021 /* beign and end should be ref */
1022 if (self->gop.num_bframes > self->gop.idr_period - 1 - 1) {
1023 if (self->gop.idr_period > 1) {
1024 self->gop.num_bframes = self->gop.idr_period - 1 - 1;
1026 self->gop.num_bframes = 0;
1028 GST_INFO_OBJECT (self, "Lowering the number of num_bframes to %d",
1029 self->gop.num_bframes);
1033 if (!gst_va_encoder_get_max_num_reference (self->encoder, self->profile,
1034 self->entrypoint, &list0, &list1)) {
1035 GST_INFO_OBJECT (self, "Failed to get the max num reference");
1040 if (list0 > self->gop.num_ref_frames)
1041 list0 = self->gop.num_ref_frames;
1042 if (list1 > self->gop.num_ref_frames)
1043 list1 = self->gop.num_ref_frames;
1046 GST_INFO_OBJECT (self,
1047 "No reference support, fallback to intra only stream");
1049 /* It does not make sense that if only the list1 exists. */
1050 self->gop.num_ref_frames = 0;
1052 self->gop.ip_period = 0;
1053 self->gop.num_bframes = 0;
1054 self->gop.b_pyramid = FALSE;
1055 self->gop.highest_pyramid_level = 0;
1056 self->gop.num_iframes = self->gop.idr_period - 1 /* The idr */ ;
1057 self->gop.ref_num_list0 = 0;
1058 self->gop.ref_num_list1 = 0;
1062 if (self->gop.num_ref_frames <= 1) {
1063 GST_INFO_OBJECT (self, "The number of reference frames is only %d,"
1064 " no B frame allowed, fallback to I/P mode", self->gop.num_ref_frames);
1065 self->gop.num_bframes = 0;
1069 /* b_pyramid needs at least 1 ref for B, besides the I/P */
1070 if (self->gop.b_pyramid && self->gop.num_ref_frames <= 2) {
1071 GST_INFO_OBJECT (self, "The number of reference frames is only %d,"
1072 " not enough for b_pyramid", self->gop.num_ref_frames);
1073 self->gop.b_pyramid = FALSE;
1076 if (list1 == 0 && self->gop.num_bframes > 0) {
1077 GST_INFO_OBJECT (self,
1078 "No hw reference support for list 1, fallback to I/P mode");
1079 self->gop.num_bframes = 0;
1080 self->gop.b_pyramid = FALSE;
1083 /* I/P mode, no list1 needed. */
1084 if (self->gop.num_bframes == 0)
1087 /* Not enough B frame, no need for b_pyramid. */
1088 if (self->gop.num_bframes <= 1)
1089 self->gop.b_pyramid = FALSE;
1091 /* b pyramid has only one backward ref. */
1092 if (self->gop.b_pyramid)
1095 if (self->gop.num_ref_frames > list0 + list1) {
1096 self->gop.num_ref_frames = list0 + list1;
1097 GST_INFO_OBJECT (self, "HW limits, lowering the number of reference"
1098 " frames to %d", self->gop.num_ref_frames);
1101 /* How many possible refs within a GOP. */
1102 gop_ref_num = (self->gop.idr_period + self->gop.num_bframes) /
1103 (self->gop.num_bframes + 1);
1105 if (self->gop.num_bframes > 0
1106 /* frame_num % (self->gop.num_bframes + 1) happens to be the end P */
1107 && (self->gop.idr_period % (self->gop.num_bframes + 1) != 1))
1110 /* Adjust reference num based on B frames and B pyramid. */
1111 if (self->gop.num_bframes == 0) {
1112 self->gop.b_pyramid = FALSE;
1113 self->gop.ref_num_list0 = self->gop.num_ref_frames;
1114 self->gop.ref_num_list1 = 0;
1115 } else if (self->gop.b_pyramid) {
1116 guint b_frames = self->gop.num_bframes;
1119 /* b pyramid has only one backward ref. */
1120 g_assert (list1 == 1);
1121 self->gop.ref_num_list1 = list1;
1122 self->gop.ref_num_list0 =
1123 self->gop.num_ref_frames - self->gop.ref_num_list1;
1125 b_frames = b_frames / 2;
1128 /* At least 1 B ref for each level, plus begin and end 2 P/I */
1130 if (b_refs + 2 > self->gop.num_ref_frames)
1133 self->gop.highest_pyramid_level++;
1134 b_frames = b_frames / 2;
1137 GST_INFO_OBJECT (self, "pyramid level is %d",
1138 self->gop.highest_pyramid_level);
1140 /* We prefer list0. Backward refs have more latency. */
1141 self->gop.ref_num_list1 = 1;
1142 self->gop.ref_num_list0 =
1143 self->gop.num_ref_frames - self->gop.ref_num_list1;
1144 /* Balance the forward and backward refs, but not cause a big latency. */
1145 while ((self->gop.num_bframes * self->gop.ref_num_list1 <= 16)
1146 && (self->gop.ref_num_list1 <= gop_ref_num)
1147 && (self->gop.ref_num_list1 < list1)
1148 && (self->gop.ref_num_list0 / self->gop.ref_num_list1 > 4)) {
1149 self->gop.ref_num_list0--;
1150 self->gop.ref_num_list1++;
1154 /* It's OK, keep slots for GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME frame. */
1155 if (self->gop.ref_num_list0 > gop_ref_num)
1156 GST_DEBUG_OBJECT (self, "num_ref_frames %d is bigger than gop_ref_num %d",
1157 self->gop.ref_num_list0, gop_ref_num);
1159 /* Include the ref picture itself. */
1160 self->gop.ip_period = 1 + self->gop.num_bframes;
1162 p_frames = gop_ref_num - 1 /* IDR */ ;
1165 if (self->gop.num_iframes > p_frames) {
1166 self->gop.num_iframes = p_frames;
1167 GST_INFO_OBJECT (self, "Too many I frames insertion, lowering it to %d",
1168 self->gop.num_iframes);
1171 if (self->gop.num_iframes > 0) {
1172 guint total_i_frames = self->gop.num_iframes + 1 /* IDR */ ;
1173 self->gop.i_period =
1174 (gop_ref_num / total_i_frames) * (self->gop.num_bframes + 1);
1178 /* init max_frame_num, max_poc */
1179 self->gop.log2_max_frame_num = _get_log2_max_num (self->gop.idr_period);
1180 self->gop.max_frame_num = (1 << self->gop.log2_max_frame_num);
1181 self->gop.log2_max_pic_order_cnt = self->gop.log2_max_frame_num + 1;
1182 self->gop.max_pic_order_cnt = (1 << self->gop.log2_max_pic_order_cnt);
1183 self->gop.num_reorder_frames = self->gop.b_pyramid ?
1184 self->gop.highest_pyramid_level * 2 + 1 /* the last P frame. */ :
1185 self->gop.ref_num_list1;
1186 /* Should not exceed the max ref num. */
1187 self->gop.num_reorder_frames =
1188 MIN (self->gop.num_reorder_frames, self->gop.num_ref_frames);
1189 self->gop.num_reorder_frames = MIN (self->gop.num_reorder_frames, 16);
1191 _create_gop_frame_types (self);
1192 _print_gop_structure (self);
1195 if (self->prop.num_ref_frames != self->gop.num_ref_frames) {
1196 self->prop.num_ref_frames = self->gop.num_ref_frames;
1197 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NUM_REF_FRAMES]);
1200 if (self->prop.num_iframes != self->gop.num_iframes) {
1201 self->prop.num_iframes = self->gop.num_iframes;
1202 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IFRAMES]);
1208 _calculate_coded_size (GstVaH264Enc * self)
1210 guint codedbuf_size = 0;
1212 if (self->profile == VAProfileH264High
1213 || self->profile == VAProfileH264MultiviewHigh
1214 || self->profile == VAProfileH264StereoHigh) {
1215 /* The number of bits of macroblock_layer( ) data for any macroblock
1216 is not greater than 128 + RawMbBits */
1217 guint RawMbBits = 0;
1218 guint BitDepthY = 8;
1219 guint BitDepthC = 8;
1221 guint MbHeightC = 8;
1223 switch (self->rt_format) {
1224 case VA_RT_FORMAT_YUV420:
1230 case VA_RT_FORMAT_YUV422:
1236 case VA_RT_FORMAT_YUV444:
1242 case VA_RT_FORMAT_YUV400:
1248 case VA_RT_FORMAT_YUV420_10:
1253 case VA_RT_FORMAT_YUV422_10:
1258 case VA_RT_FORMAT_YUV444_10:
1265 g_assert_not_reached ();
1269 /* The variable RawMbBits is derived as
1270 * RawMbBits = 256 * BitDepthY + 2 * MbWidthC * MbHeightC * BitDepthC */
1271 RawMbBits = 256 * BitDepthY + 2 * MbWidthC * MbHeightC * BitDepthC;
1272 codedbuf_size = (self->mb_width * self->mb_height) * (128 + RawMbBits) / 8;
1274 /* The number of bits of macroblock_layer( ) data for any macroblock
1275 * is not greater than 3200 */
1276 codedbuf_size = (self->mb_width * self->mb_height) * (3200 / 8);
1279 /* Account for SPS header */
1280 /* XXX: exclude scaling lists, MVC/SVC extensions */
1281 codedbuf_size += 4 /* start code */ + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
1282 MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
1284 /* Account for PPS header */
1285 /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
1286 codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
1288 /* Account for slice header */
1290 self->num_slices * (4 + GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
1292 /* Add 5% for safety */
1293 self->codedbuf_size = (guint) ((gfloat) codedbuf_size * 1.05);
1295 GST_DEBUG_OBJECT (self, "Calculate codedbuf size: %u", self->codedbuf_size);
1299 _get_rtformat (GstVaH264Enc * self, GstVideoFormat format)
1303 chroma = gst_va_chroma_from_video_format (format);
1305 /* Check whether the rtformat is supported. */
1306 if (chroma != VA_RT_FORMAT_YUV420) {
1307 GST_ERROR_OBJECT (self, "Unsupported chroma for video format: %s",
1308 gst_video_format_to_string (format));
1316 _init_packed_headers (GstVaH264Enc * self)
1318 guint32 packed_headers;
1319 guint32 desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE /* SPS */
1320 | VA_ENC_PACKED_HEADER_PICTURE /* PPS */
1321 | VA_ENC_PACKED_HEADER_SLICE /* Slice headers */
1322 | VA_ENC_PACKED_HEADER_RAW_DATA; /* SEI, AUD, etc. */
1324 self->packed_headers = 0;
1326 packed_headers = gst_va_encoder_get_packed_headers (self->encoder,
1327 self->profile, self->entrypoint);
1329 if (packed_headers == 0)
1332 if (desired_packed_headers & ~packed_headers) {
1333 GST_INFO_OBJECT (self, "Driver does not support some wanted packed headers "
1334 "(wanted %#x, found %#x)", desired_packed_headers, packed_headers);
1337 self->packed_headers = desired_packed_headers & packed_headers;
1344 _decide_profile (GstVaH264Enc * self)
1346 gboolean ret = FALSE;
1347 GstVideoFormat in_format;
1350 GstCaps *allowed_caps = NULL;
1351 guint num_structures, i;
1352 GstStructure *structure;
1353 const GValue *v_profile;
1354 GPtrArray *candidates = NULL;
1355 gchar *profile_name;
1357 candidates = g_ptr_array_new_with_free_func (g_free);
1359 /* First, check whether the downstream requires a specified profile. */
1360 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (self));
1362 allowed_caps = gst_pad_query_caps (GST_VIDEO_ENCODER_SRC_PAD (self), NULL);
1364 if (allowed_caps && !gst_caps_is_empty (allowed_caps)) {
1365 num_structures = gst_caps_get_size (allowed_caps);
1366 for (i = 0; i < num_structures; i++) {
1367 structure = gst_caps_get_structure (allowed_caps, i);
1368 v_profile = gst_structure_get_value (structure, "profile");
1372 if (G_VALUE_HOLDS_STRING (v_profile)) {
1373 profile_name = g_strdup (g_value_get_string (v_profile));
1374 g_ptr_array_add (candidates, profile_name);
1375 } else if (GST_VALUE_HOLDS_LIST (v_profile)) {
1378 for (j = 0; j < gst_value_list_get_size (v_profile); j++) {
1379 const GValue *p = gst_value_list_get_value (v_profile, j);
1383 profile_name = g_strdup (g_value_get_string (p));
1384 g_ptr_array_add (candidates, profile_name);
1390 if (candidates->len == 0) {
1391 GST_ERROR_OBJECT (self, "No available profile in caps");
1396 in_format = GST_VIDEO_INFO_FORMAT (&self->in_info);
1397 rt_format = _get_rtformat (self, in_format);
1399 GST_ERROR_OBJECT (self, "unsupported video format %s",
1400 gst_video_format_to_string (in_format));
1405 /* Find the suitable profile by features and check the HW
1408 for (i = 0; i < candidates->len; i++) {
1409 profile_name = g_ptr_array_index (candidates, i);
1411 /* dct8x8 require at least high profile. */
1412 if (self->use_dct8x8) {
1413 if (!g_strstr_len (profile_name, -1, "high"))
1417 /* cabac require at least main profile. */
1418 if (self->use_cabac) {
1419 if (!g_strstr_len (profile_name, -1, "main")
1420 && !g_strstr_len (profile_name, -1, "high"))
1424 /* baseline only support I/P mode. */
1425 if (self->gop.num_bframes > 0) {
1426 if (g_strstr_len (profile_name, -1, "baseline"))
1430 profile = gst_va_profile_from_name (H264, profile_name);
1431 if (profile == VAProfileNone)
1434 if (!gst_va_encoder_has_profile_and_entrypoint (self->encoder,
1435 profile, VAEntrypointEncSlice))
1438 if ((rt_format & gst_va_encoder_get_rtformat (self->encoder,
1439 profile, VAEntrypointEncSlice)) == 0)
1442 self->profile = profile;
1443 self->entrypoint = VAEntrypointEncSlice;
1444 self->rt_format = rt_format;
1449 /* Just use the first HW available profile and disable features if
1451 profile_name = NULL;
1452 for (i = 0; i < candidates->len; i++) {
1453 profile_name = g_ptr_array_index (candidates, i);
1454 profile = gst_va_profile_from_name (H264, profile_name);
1455 if (profile == VAProfileNone)
1458 if (!gst_va_encoder_has_profile_and_entrypoint (self->encoder,
1459 profile, VAEntrypointEncSlice))
1462 if ((rt_format & gst_va_encoder_get_rtformat (self->encoder,
1463 profile, VAEntrypointEncSlice)) == 0)
1466 self->profile = profile;
1467 self->entrypoint = VAEntrypointEncSlice;
1468 self->rt_format = rt_format;
1475 if (self->use_dct8x8 && !g_strstr_len (profile_name, -1, "high")) {
1476 GST_INFO_OBJECT (self, "Disable dct8x8, profile %s does not support it",
1477 gst_va_profile_name (self->profile));
1478 self->use_dct8x8 = FALSE;
1479 self->prop.use_dct8x8 = FALSE;
1480 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DCT8X8]);
1483 if (self->use_cabac && (!g_strstr_len (profile_name, -1, "main")
1484 && !g_strstr_len (profile_name, -1, "high"))) {
1485 GST_INFO_OBJECT (self, "Disable cabac, profile %s does not support it",
1486 gst_va_profile_name (self->profile));
1487 self->use_cabac = FALSE;
1488 self->prop.use_cabac = FALSE;
1489 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CABAC]);
1492 if (self->gop.num_bframes > 0 && g_strstr_len (profile_name, -1, "baseline")) {
1493 GST_INFO_OBJECT (self, "No B frames, profile %s does not support it",
1494 gst_va_profile_name (self->profile));
1495 self->gop.num_bframes = 0;
1496 self->gop.b_pyramid = 0;
1500 g_clear_pointer (&candidates, g_ptr_array_unref);
1501 g_clear_pointer (&allowed_caps, gst_caps_unref);
1504 GST_INFO_OBJECT (self, "Select the profile %s",
1505 gst_va_profile_name (profile));
1507 GST_ERROR_OBJECT (self, "Failed to find an available profile");
1513 /* Clear all the info of last reconfig and set the fields based on
1514 * property. The reconfig may change these fields because of the
1515 * profile/level and HW limitation. */
1517 gst_va_h264_enc_reset_state (GstVaH264Enc * self)
1521 self->profile = VAProfileNone;
1522 self->entrypoint = 0;
1523 self->rt_format = 0;
1524 self->codedbuf_size = 0;
1526 self->frame_duration = GST_CLOCK_TIME_NONE;
1527 self->input_frame_count = 0;
1528 self->output_frame_count = 0;
1530 self->level_idc = 0;
1531 self->level_str = NULL;
1533 self->mb_height = 0;
1534 self->use_cabac = self->prop.use_cabac;
1535 self->use_dct8x8 = self->prop.use_dct8x8;
1536 self->use_trellis = self->prop.use_trellis;
1537 self->num_slices = self->prop.num_slices;
1539 self->gop.idr_period = self->prop.key_int_max;
1540 self->gop.i_period = 0;
1541 self->gop.total_idr_count = 0;
1542 self->gop.ip_period = 0;
1543 self->gop.num_bframes = self->prop.num_bframes;
1544 self->gop.b_pyramid = self->prop.b_pyramid;
1545 self->gop.highest_pyramid_level = 0;
1546 self->gop.num_iframes = self->prop.num_iframes;
1547 memset (self->gop.frame_types, 0, sizeof (self->gop.frame_types));
1548 self->gop.cur_frame_index = 0;
1549 self->gop.cur_frame_num = 0;
1550 self->gop.max_frame_num = 0;
1551 self->gop.log2_max_frame_num = 0;
1552 self->gop.max_pic_order_cnt = 0;
1553 self->gop.log2_max_pic_order_cnt = 0;
1554 self->gop.num_ref_frames = self->prop.num_ref_frames;
1555 self->gop.ref_num_list0 = 0;
1556 self->gop.ref_num_list1 = 0;
1557 self->gop.num_reorder_frames = 0;
1559 self->rc.rc_ctrl_mode = self->prop.rc_ctrl;
1560 self->rc.min_qp = self->prop.min_qp;
1561 self->rc.max_qp = self->prop.max_qp;
1562 self->rc.qp_i = self->prop.qp_i;
1563 self->rc.qp_p = self->prop.qp_p;
1564 self->rc.qp_b = self->prop.qp_b;
1565 self->rc.mbbrc = self->prop.mbbrc;
1566 self->rc.max_bitrate = 0;
1567 self->rc.target_bitrate = 0;
1568 self->rc.target_percentage = self->prop.target_percentage;
1569 self->rc.target_usage = self->prop.target_usage;
1570 self->rc.max_bitrate_bits = 0;
1571 self->rc.target_bitrate_bits = 0;
1572 self->rc.cpb_size = self->prop.cpb_size;
1573 self->rc.cpb_length_bits = 0;
1575 memset (&self->sequence_hdr, 0, sizeof (GstH264SPS));
1579 gst_va_h264_enc_reconfig (GstVaH264Enc * self)
1581 gst_va_h264_enc_reset_state (self);
1583 self->width = GST_VIDEO_INFO_WIDTH (&self->in_info);
1584 self->height = GST_VIDEO_INFO_HEIGHT (&self->in_info);
1586 self->mb_width = GST_ROUND_UP_16 (self->width) / 16;
1587 self->mb_height = GST_ROUND_UP_16 (self->height) / 16;
1589 /* Frame rate is needed for rate control and PTS setting. */
1590 if (GST_VIDEO_INFO_FPS_N (&self->in_info) == 0
1591 || GST_VIDEO_INFO_FPS_D (&self->in_info) == 0) {
1592 GST_INFO_OBJECT (self, "Unknown framerate, just set to 30 fps");
1593 GST_VIDEO_INFO_FPS_N (&self->in_info) = 30;
1594 GST_VIDEO_INFO_FPS_D (&self->in_info) = 1;
1596 self->frame_duration = gst_util_uint64_scale (GST_SECOND,
1597 GST_VIDEO_INFO_FPS_D (&self->in_info),
1598 GST_VIDEO_INFO_FPS_N (&self->in_info));
1600 GST_DEBUG_OBJECT (self, "resolution:%dx%d, MB size: %dx%d,"
1601 " frame duration is %" GST_TIME_FORMAT,
1602 self->width, self->height, self->mb_width, self->mb_height,
1603 GST_TIME_ARGS (self->frame_duration));
1605 if (!_decide_profile (self))
1608 _validate_parameters (self);
1610 _ensure_rate_control (self);
1612 if (!_calculate_level (self))
1615 _generate_gop_structure (self);
1616 _calculate_coded_size (self);
1619 /* num_bframes are modified several times before */
1620 if (self->prop.num_bframes != self->gop.num_bframes) {
1621 self->prop.num_bframes = self->gop.num_bframes;
1622 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BFRAMES]);
1625 if (self->prop.b_pyramid != self->gop.b_pyramid) {
1626 self->prop.b_pyramid = self->gop.b_pyramid;
1627 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_B_PYRAMID]);
1630 if (!_init_packed_headers (self))
1637 gst_va_h264_enc_push_frame (GstVaH264Enc * self, GstVideoCodecFrame * gst_frame,
1640 GstVaH264EncFrame *frame;
1642 g_return_val_if_fail (self->gop.cur_frame_index <= self->gop.idr_period,
1646 /* Begin a new GOP, should have a empty reorder_list. */
1647 if (self->gop.cur_frame_index == self->gop.idr_period) {
1648 g_assert (g_queue_is_empty (&self->reorder_list));
1649 self->gop.cur_frame_index = 0;
1650 self->gop.cur_frame_num = 0;
1653 frame = _enc_frame (gst_frame);
1655 ((self->gop.cur_frame_index * 2) % self->gop.max_pic_order_cnt);
1657 if (self->gop.cur_frame_index == 0) {
1658 g_assert (frame->poc == 0);
1659 GST_LOG_OBJECT (self, "system_frame_number: %d, an IDR frame, starts"
1660 " a new GOP", gst_frame->system_frame_number);
1662 g_queue_clear_full (&self->ref_list,
1663 (GDestroyNotify) gst_video_codec_frame_unref);
1666 frame->type = self->gop.frame_types[self->gop.cur_frame_index].slice_type;
1667 frame->is_ref = self->gop.frame_types[self->gop.cur_frame_index].is_ref;
1668 frame->pyramid_level =
1669 self->gop.frame_types[self->gop.cur_frame_index].pyramid_level;
1670 frame->left_ref_poc_diff =
1671 self->gop.frame_types[self->gop.cur_frame_index].left_ref_poc_diff;
1672 frame->right_ref_poc_diff =
1673 self->gop.frame_types[self->gop.cur_frame_index].right_ref_poc_diff;
1675 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (gst_frame)) {
1676 GST_DEBUG_OBJECT (self, "system_frame_number: %d, a force key frame,"
1677 " promote its type from %s to %s", gst_frame->system_frame_number,
1678 _slice_type_name (frame->type), _slice_type_name (GST_H264_I_SLICE));
1679 frame->type = GST_H264_I_SLICE;
1680 frame->is_ref = TRUE;
1683 GST_LOG_OBJECT (self, "Push frame, system_frame_number: %d, poc %d, "
1684 "frame type %s", gst_frame->system_frame_number, frame->poc,
1685 _slice_type_name (frame->type));
1687 self->gop.cur_frame_index++;
1688 g_queue_push_tail (&self->reorder_list,
1689 gst_video_codec_frame_ref (gst_frame));
1692 /* ensure the last one a non-B and end the GOP. */
1693 if (last && self->gop.cur_frame_index < self->gop.idr_period) {
1694 GstVideoCodecFrame *last_frame;
1696 /* Ensure next push will start a new GOP. */
1697 self->gop.cur_frame_index = self->gop.idr_period;
1699 if (!g_queue_is_empty (&self->reorder_list)) {
1700 last_frame = g_queue_peek_tail (&self->reorder_list);
1701 frame = _enc_frame (last_frame);
1702 if (frame->type == GST_H264_B_SLICE) {
1703 frame->type = GST_H264_P_SLICE;
1704 frame->is_ref = TRUE;
1712 struct RefFramesCount
1719 _count_backward_ref_num (gpointer data, gpointer user_data)
1721 GstVaH264EncFrame *frame = _enc_frame (data);
1722 struct RefFramesCount *count = (struct RefFramesCount *) user_data;
1724 g_assert (frame->poc != count->poc);
1725 if (frame->poc > count->poc)
1729 static GstVideoCodecFrame *
1730 _pop_pyramid_b_frame (GstVaH264Enc * self)
1734 GstVaH264EncFrame *b_vaframe;
1735 GstVideoCodecFrame *b_frame;
1736 struct RefFramesCount count;
1738 g_assert (self->gop.ref_num_list1 == 1);
1743 /* Find the lowest level with smallest poc. */
1744 for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
1745 GstVaH264EncFrame *vaf;
1746 GstVideoCodecFrame *f;
1748 f = g_queue_peek_nth (&self->reorder_list, i);
1752 b_vaframe = _enc_frame (b_frame);
1757 vaf = _enc_frame (f);
1758 if (b_vaframe->pyramid_level < vaf->pyramid_level) {
1765 if (b_vaframe->poc > vaf->poc) {
1773 /* Check whether its refs are already poped. */
1774 g_assert (b_vaframe->left_ref_poc_diff != 0);
1775 g_assert (b_vaframe->right_ref_poc_diff != 0);
1776 for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
1777 GstVaH264EncFrame *vaf;
1778 GstVideoCodecFrame *f;
1780 f = g_queue_peek_nth (&self->reorder_list, i);
1785 vaf = _enc_frame (f);
1786 if (vaf->poc == b_vaframe->poc + b_vaframe->left_ref_poc_diff
1787 || vaf->poc == b_vaframe->poc + b_vaframe->right_ref_poc_diff) {
1795 /* Ensure we already have enough backward refs */
1797 count.poc = b_vaframe->poc;
1798 g_queue_foreach (&self->ref_list, (GFunc) _count_backward_ref_num, &count);
1799 if (count.num >= self->gop.ref_num_list1) {
1800 GstVideoCodecFrame *f;
1802 /* it will unref at pop_frame */
1803 f = g_queue_pop_nth (&self->reorder_list, index);
1804 g_assert (f == b_frame);
1813 gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVideoCodecFrame ** out_frame)
1815 GstVaH264EncFrame *vaframe;
1816 GstVideoCodecFrame *frame;
1817 struct RefFramesCount count;
1819 g_return_val_if_fail (self->gop.cur_frame_index <= self->gop.idr_period,
1824 if (g_queue_is_empty (&self->reorder_list))
1827 /* Return the last pushed non-B immediately. */
1828 frame = g_queue_peek_tail (&self->reorder_list);
1829 vaframe = _enc_frame (frame);
1830 if (vaframe->type != GST_H264_B_SLICE) {
1831 frame = g_queue_pop_tail (&self->reorder_list);
1835 if (self->gop.b_pyramid) {
1836 frame = _pop_pyramid_b_frame (self);
1842 g_assert (self->gop.ref_num_list1 > 0);
1844 /* If GOP end, pop anyway. */
1845 if (self->gop.cur_frame_index == self->gop.idr_period) {
1846 frame = g_queue_pop_head (&self->reorder_list);
1850 /* Ensure we already have enough backward refs */
1851 frame = g_queue_peek_head (&self->reorder_list);
1852 vaframe = _enc_frame (frame);
1854 count.poc = vaframe->poc;
1855 g_queue_foreach (&self->ref_list, _count_backward_ref_num, &count);
1856 if (count.num >= self->gop.ref_num_list1) {
1857 frame = g_queue_pop_head (&self->reorder_list);
1864 g_assert (self->gop.cur_frame_num < self->gop.max_frame_num);
1866 vaframe = _enc_frame (frame);
1867 vaframe->frame_num = self->gop.cur_frame_num;
1869 /* Add the frame number for ref frames. */
1870 if (vaframe->is_ref)
1871 self->gop.cur_frame_num++;
1873 if (vaframe->frame_num == 0)
1874 self->gop.total_idr_count++;
1876 if (self->gop.b_pyramid && vaframe->type == GST_H264_B_SLICE) {
1877 GST_LOG_OBJECT (self, "pop a pyramid B frame with system_frame_number:"
1878 " %d, poc: %d, frame num: %d, is_ref: %s, level %d",
1879 frame->system_frame_number, vaframe->poc, vaframe->frame_num,
1880 vaframe->is_ref ? "true" : "false", vaframe->pyramid_level);
1882 GST_LOG_OBJECT (self, "pop a frame with system_frame_number: %d,"
1883 " frame type: %s, poc: %d, frame num: %d, is_ref: %s",
1884 frame->system_frame_number, _slice_type_name (vaframe->type),
1885 vaframe->poc, vaframe->frame_num, vaframe->is_ref ? "true" : "false");
1888 /* unref frame popped from queue or pyramid b_frame */
1889 gst_video_codec_frame_unref (frame);
1894 static inline gboolean
1895 _fill_sps (GstVaH264Enc * self, VAEncSequenceParameterBufferH264 * seq_param)
1897 GstH264Profile profile;
1898 guint32 constraint_set0_flag, constraint_set1_flag;
1899 guint32 constraint_set2_flag, constraint_set3_flag;
1900 guint32 max_dec_frame_buffering;
1902 /* let max_num_ref_frames <= MaxDpbFrames. */
1903 max_dec_frame_buffering =
1904 MIN (self->gop.num_ref_frames + 1 /* Last frame before bump */ ,
1905 16 /* DPB_MAX_SIZE */ );
1907 constraint_set0_flag = 0;
1908 constraint_set1_flag = 0;
1909 constraint_set2_flag = 0;
1910 constraint_set3_flag = 0;
1912 switch (self->profile) {
1913 case VAProfileH264ConstrainedBaseline:
1914 profile = GST_H264_PROFILE_BASELINE;
1915 /* A.2.1 (baseline profile constraints) */
1916 constraint_set0_flag = 1;
1917 constraint_set1_flag = 1;
1919 case VAProfileH264Main:
1920 profile = GST_H264_PROFILE_MAIN;
1921 /* A.2.2 (main profile constraints) */
1922 constraint_set1_flag = 1;
1924 case VAProfileH264High:
1925 case VAProfileH264MultiviewHigh:
1926 case VAProfileH264StereoHigh:
1927 profile = GST_H264_PROFILE_HIGH;
1933 /* seq_scaling_matrix_present_flag not supported now */
1934 g_assert (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag == 0);
1935 /* pic_order_cnt_type only support 0 now */
1936 g_assert (seq_param->seq_fields.bits.pic_order_cnt_type == 0);
1937 /* only progressive frames encoding is supported now */
1938 g_assert (seq_param->seq_fields.bits.frame_mbs_only_flag);
1941 GST_DEBUG_OBJECT (self, "filling SPS");
1942 self->sequence_hdr = (GstH264SPS) {
1944 .profile_idc = profile,
1945 .constraint_set0_flag = constraint_set0_flag,
1946 .constraint_set1_flag = constraint_set1_flag,
1947 .constraint_set2_flag = constraint_set2_flag,
1948 .constraint_set3_flag = constraint_set3_flag,
1949 .level_idc = self->level_idc,
1951 .chroma_format_idc = seq_param->seq_fields.bits.chroma_format_idc,
1952 .bit_depth_luma_minus8 = seq_param->bit_depth_luma_minus8,
1953 .bit_depth_chroma_minus8 = seq_param->bit_depth_chroma_minus8,
1955 .log2_max_frame_num_minus4 =
1956 seq_param->seq_fields.bits.log2_max_frame_num_minus4,
1957 .pic_order_cnt_type = seq_param->seq_fields.bits.pic_order_cnt_type,
1958 .log2_max_pic_order_cnt_lsb_minus4 =
1959 seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4,
1961 .num_ref_frames = seq_param->max_num_ref_frames,
1962 .gaps_in_frame_num_value_allowed_flag = 0,
1963 .pic_width_in_mbs_minus1 = seq_param->picture_width_in_mbs - 1,
1964 .pic_height_in_map_units_minus1 =
1965 (seq_param->seq_fields.bits.frame_mbs_only_flag ?
1966 seq_param->picture_height_in_mbs - 1 :
1967 seq_param->picture_height_in_mbs / 2 - 1),
1968 .frame_mbs_only_flag = seq_param->seq_fields.bits.frame_mbs_only_flag,
1969 .mb_adaptive_frame_field_flag = 0,
1970 .direct_8x8_inference_flag =
1971 seq_param->seq_fields.bits.direct_8x8_inference_flag,
1972 .frame_cropping_flag = seq_param->frame_cropping_flag,
1973 .frame_crop_left_offset = seq_param->frame_crop_left_offset,
1974 .frame_crop_right_offset = seq_param->frame_crop_right_offset,
1975 .frame_crop_top_offset = seq_param->frame_crop_top_offset,
1976 .frame_crop_bottom_offset = seq_param->frame_crop_bottom_offset,
1978 .vui_parameters_present_flag = seq_param->vui_parameters_present_flag,
1980 .aspect_ratio_info_present_flag =
1981 seq_param->vui_fields.bits.aspect_ratio_info_present_flag,
1982 .aspect_ratio_idc = seq_param->aspect_ratio_idc,
1983 .sar_width = seq_param->sar_width,
1984 .sar_height = seq_param->sar_height,
1985 .overscan_info_present_flag = 0,
1986 .overscan_appropriate_flag = 0,
1987 .chroma_loc_info_present_flag = 0,
1988 .timing_info_present_flag =
1989 seq_param->vui_fields.bits.timing_info_present_flag,
1990 .num_units_in_tick = seq_param->num_units_in_tick,
1991 .time_scale = seq_param->time_scale,
1992 .fixed_frame_rate_flag = seq_param->vui_fields.bits.fixed_frame_rate_flag,
1994 /* We do not write hrd and no need for buffering period SEI. */
1995 .nal_hrd_parameters_present_flag = 0,
1996 .vcl_hrd_parameters_present_flag = 0,
1998 .low_delay_hrd_flag = seq_param->vui_fields.bits.low_delay_hrd_flag,
1999 .pic_struct_present_flag = 1,
2000 .bitstream_restriction_flag =
2001 seq_param->vui_fields.bits.bitstream_restriction_flag,
2002 .motion_vectors_over_pic_boundaries_flag =
2003 seq_param->vui_fields.bits.motion_vectors_over_pic_boundaries_flag,
2004 .max_bytes_per_pic_denom = 2,
2005 .max_bits_per_mb_denom = 1,
2006 .log2_max_mv_length_horizontal =
2007 seq_param->vui_fields.bits.log2_max_mv_length_horizontal,
2008 .log2_max_mv_length_vertical =
2009 seq_param->vui_fields.bits.log2_max_mv_length_vertical,
2010 .num_reorder_frames = self->gop.num_reorder_frames,
2011 .max_dec_frame_buffering = max_dec_frame_buffering,
2020 _add_sequence_header (GstVaH264Enc * self, GstVaH264EncFrame * frame)
2023 #define SPS_SIZE 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE + MAX_VUI_PARAMS_SIZE + \
2024 2 * MAX_HRD_PARAMS_SIZE) / 8
2025 guint8 packed_sps[SPS_SIZE] = { 0, };
2028 size = sizeof (packed_sps);
2029 if (gst_h264_bit_writer_sps (&self->sequence_hdr, TRUE, packed_sps,
2030 &size) != GST_H264_BIT_WRITER_OK) {
2031 GST_ERROR_OBJECT (self, "Failed to generate the sequence header");
2035 if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
2036 VAEncPackedHeaderSequence, packed_sps, size, FALSE)) {
2037 GST_ERROR_OBJECT (self, "Failed to add the packed sequence header");
2045 _fill_sequence_param (GstVaH264Enc * self,
2046 VAEncSequenceParameterBufferH264 * sequence)
2048 gboolean direct_8x8_inference_flag = TRUE;
2050 g_assert (self->gop.log2_max_frame_num >= 4);
2051 g_assert (self->gop.log2_max_pic_order_cnt >= 4);
2053 /* A.2.3 Extended profile:
2054 * Sequence parameter sets shall have direct_8x8_inference_flag
2057 * A.3.3 Profile-specific level limits:
2058 * direct_8x8_inference_flag is not relevant to the Baseline,
2059 * Constrained Baseline, Constrained High, High 10 Intra, High 4:2:2
2060 * Intra, High 4:4:4 Intra, and CAVLC 4:4:4 Intra profiles as these
2061 * profiles do not allow B slice types, and
2062 * direct_8x8_inference_flag is equal to 1 for all levels of the
2063 * Extended profile. Table A-4. We only have constrained baseline
2065 if (self->profile == VAProfileH264ConstrainedBaseline)
2066 direct_8x8_inference_flag = FALSE;
2069 *sequence = (VAEncSequenceParameterBufferH264) {
2070 .seq_parameter_set_id = 0,
2071 .level_idc = self->level_idc,
2073 self->gop.i_period > 0 ? self->gop.i_period : self->gop.idr_period,
2074 .intra_idr_period = self->gop.idr_period,
2075 .ip_period = self->gop.ip_period,
2076 .bits_per_second = self->rc.target_bitrate_bits,
2077 .max_num_ref_frames = self->gop.num_ref_frames,
2078 .picture_width_in_mbs = self->mb_width,
2079 .picture_height_in_mbs = self->mb_height,
2081 .seq_fields.bits = {
2082 /* Only support 4:2:0 now. */
2083 .chroma_format_idc = 1,
2084 .frame_mbs_only_flag = 1,
2085 .mb_adaptive_frame_field_flag = FALSE,
2086 .seq_scaling_matrix_present_flag = FALSE,
2087 .direct_8x8_inference_flag = direct_8x8_inference_flag,
2088 .log2_max_frame_num_minus4 = self->gop.log2_max_frame_num - 4,
2089 .pic_order_cnt_type = 0,
2090 .log2_max_pic_order_cnt_lsb_minus4 = self->gop.log2_max_pic_order_cnt - 4,
2092 .bit_depth_luma_minus8 = 0,
2093 .bit_depth_chroma_minus8 = 0,
2095 .vui_parameters_present_flag = TRUE,
2096 .vui_fields.bits = {
2097 .aspect_ratio_info_present_flag = TRUE,
2098 .timing_info_present_flag = TRUE,
2099 .bitstream_restriction_flag = TRUE,
2100 .log2_max_mv_length_horizontal = 15,
2101 .log2_max_mv_length_vertical = 15,
2102 .fixed_frame_rate_flag = 1,
2103 .low_delay_hrd_flag = 0,
2104 .motion_vectors_over_pic_boundaries_flag = TRUE,
2106 .aspect_ratio_idc = 0xff,
2107 /* FIXME: what if no framerate info is provided */
2108 .sar_width = GST_VIDEO_INFO_PAR_N (&self->in_info),
2109 .sar_height = GST_VIDEO_INFO_PAR_D (&self->in_info),
2110 .num_units_in_tick = GST_VIDEO_INFO_FPS_D (&self->in_info),
2111 .time_scale = GST_VIDEO_INFO_FPS_N (&self->in_info) * 2,
2115 /* frame_cropping_flag */
2116 if (self->width & 15 || self->height & 15) {
2117 static const guint SubWidthC[] = { 1, 2, 2, 1 };
2118 static const guint SubHeightC[] = { 1, 2, 1, 1 };
2119 const guint CropUnitX =
2120 SubWidthC[sequence->seq_fields.bits.chroma_format_idc];
2121 const guint CropUnitY =
2122 SubHeightC[sequence->seq_fields.bits.chroma_format_idc] *
2123 (2 - sequence->seq_fields.bits.frame_mbs_only_flag);
2125 sequence->frame_cropping_flag = 1;
2126 sequence->frame_crop_left_offset = 0;
2127 sequence->frame_crop_right_offset = (16 * self->mb_width -
2128 self->width) / CropUnitX;
2129 sequence->frame_crop_top_offset = 0;
2130 sequence->frame_crop_bottom_offset = (16 * self->mb_height -
2131 self->height) / CropUnitY;
2136 _add_sequence_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture,
2137 VAEncSequenceParameterBufferH264 * sequence)
2139 if (!gst_va_encoder_add_param (self->encoder, picture,
2140 VAEncSequenceParameterBufferType, sequence, sizeof (*sequence))) {
2141 GST_ERROR_OBJECT (self, "Failed to create the sequence parameter");
2149 _add_rate_control_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
2151 uint32_t window_size;
2152 struct VAEncMiscParameterRateControlWrap
2154 VAEncMiscParameterType type;
2155 VAEncMiscParameterRateControl rate_control;
2158 if (self->rc.rc_ctrl_mode == VA_RC_CQP)
2161 window_size = self->rc.rc_ctrl_mode == VA_RC_VBR ?
2162 self->rc.max_bitrate_bits / 2 : self->rc.max_bitrate_bits;
2165 rate_control = (struct VAEncMiscParameterRateControlWrap) {
2166 .type = VAEncMiscParameterTypeRateControl,
2168 .bits_per_second = self->rc.max_bitrate_bits,
2169 .target_percentage = self->rc.target_percentage,
2170 .window_size = window_size,
2171 .initial_qp = self->rc.qp_i,
2172 .min_qp = self->rc.min_qp,
2173 .max_qp = self->rc.max_qp,
2174 .rc_flags.bits.mb_rate_control = self->rc.mbbrc,
2175 .quality_factor = 0,
2180 if (!gst_va_encoder_add_param (self->encoder, picture,
2181 VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
2182 GST_ERROR_OBJECT (self, "Failed to create the race control parameter");
2190 _add_hrd_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
2195 VAEncMiscParameterType type;
2196 VAEncMiscParameterHRD hrd;
2198 .type = VAEncMiscParameterTypeHRD,
2200 .buffer_size = self->rc.cpb_length_bits,
2201 .initial_buffer_fullness = self->rc.cpb_length_bits / 2,
2206 if (self->rc.rc_ctrl_mode == VA_RC_CQP || self->rc.rc_ctrl_mode == VA_RC_VCM)
2209 g_assert (self->rc.max_bitrate_bits > 0);
2212 if (!gst_va_encoder_add_param (self->encoder, picture,
2213 VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
2214 GST_ERROR_OBJECT (self, "Failed to create the HRD parameter");
2222 _add_quality_level_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
2227 VAEncMiscParameterType type;
2228 VAEncMiscParameterBufferQualityLevel ql;
2230 .type = VAEncMiscParameterTypeQualityLevel,
2231 .ql.quality_level = self->rc.target_usage,
2235 if (self->rc.target_usage == 0)
2238 if (!gst_va_encoder_add_param (self->encoder, picture,
2239 VAEncMiscParameterBufferType, &quality_level,
2240 sizeof (quality_level))) {
2241 GST_ERROR_OBJECT (self, "Failed to create the quality level parameter");
2249 _add_frame_rate_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
2254 VAEncMiscParameterType type;
2255 VAEncMiscParameterFrameRate fr;
2257 .type = VAEncMiscParameterTypeFrameRate,
2258 /* denominator = framerate >> 16 & 0xffff;
2259 * numerator = framerate & 0xffff; */
2260 .fr.framerate = (GST_VIDEO_INFO_FPS_N (&self->in_info) & 0xffff) |
2261 ((GST_VIDEO_INFO_FPS_D (&self->in_info) & 0xffff) << 16)
2265 if (!gst_va_encoder_add_param (self->encoder, picture,
2266 VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
2267 GST_ERROR_OBJECT (self, "Failed to create the frame rate parameter");
2275 _add_trellis_parameter (GstVaH264Enc * self, GstVaEncodePicture * picture)
2280 VAEncMiscParameterType type;
2281 VAEncMiscParameterQuantization tr;
2283 .type = VAEncMiscParameterTypeQuantization,
2284 .tr.quantization_flags.bits = {
2285 .disable_trellis = 0,
2286 .enable_trellis_I = 1,
2287 .enable_trellis_B = 1,
2288 .enable_trellis_P = 1,
2293 if (!self->use_trellis)
2296 if (!gst_va_encoder_add_param (self->encoder, picture,
2297 VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
2298 GST_ERROR_OBJECT (self, "Failed to create the trellis parameter");
2305 static inline gboolean
2306 _fill_picture_parameter (GstVaH264Enc * self, GstVaH264EncFrame * frame,
2307 VAEncPictureParameterBufferH264 * pic_param)
2312 *pic_param = (VAEncPictureParameterBufferH264) {
2313 .CurrPic.picture_id = gst_va_encode_picture_get_reconstruct_surface (frame->picture),
2314 .CurrPic.TopFieldOrderCnt = frame->poc,
2315 .coded_buf = frame->picture->coded_buffer,
2316 /* Only support one sps and pps now. */
2317 .pic_parameter_set_id = 0,
2318 .seq_parameter_set_id = 0,
2319 /* means last encoding picture, EOS nal added. */
2320 .last_picture = frame->last_frame,
2321 .frame_num = frame->frame_num,
2323 .pic_init_qp = self->rc.qp_i,
2324 /* Use slice's these fields to control ref num. */
2325 .num_ref_idx_l0_active_minus1 = 0,
2326 .num_ref_idx_l1_active_minus1 = 0,
2327 .chroma_qp_index_offset = 0,
2328 .second_chroma_qp_index_offset = 0,
2329 /* picture fields */
2330 .pic_fields.bits.idr_pic_flag = (frame->frame_num == 0),
2331 .pic_fields.bits.reference_pic_flag = frame->is_ref,
2332 .pic_fields.bits.entropy_coding_mode_flag = self->use_cabac,
2333 .pic_fields.bits.weighted_pred_flag = 0,
2334 .pic_fields.bits.weighted_bipred_idc = 0,
2335 .pic_fields.bits.constrained_intra_pred_flag = 0,
2336 .pic_fields.bits.transform_8x8_mode_flag = self->use_dct8x8,
2337 /* enable debloking */
2338 .pic_fields.bits.deblocking_filter_control_present_flag = 1,
2339 .pic_fields.bits.redundant_pic_cnt_present_flag = 0,
2340 /* bottom_field_pic_order_in_frame_present_flag */
2341 .pic_fields.bits.pic_order_present_flag = 0,
2342 .pic_fields.bits.pic_scaling_matrix_present_flag = 0,
2346 /* Non I frame, construct reference list. */
2348 if (frame->type != GST_H264_I_SLICE) {
2349 GstVaH264EncFrame *f;
2351 if (g_queue_is_empty (&self->ref_list)) {
2352 GST_ERROR_OBJECT (self, "No reference found for frame type %s",
2353 _slice_type_name (frame->type));
2357 g_assert (g_queue_get_length (&self->ref_list) <= self->gop.num_ref_frames);
2359 /* ref frames in queue are already sorted by frame_num. */
2360 for (; i < g_queue_get_length (&self->ref_list); i++) {
2361 f = _enc_frame (g_queue_peek_nth (&self->ref_list, i));
2363 pic_param->ReferenceFrames[i].picture_id =
2364 gst_va_encode_picture_get_reconstruct_surface (f->picture);
2365 pic_param->ReferenceFrames[i].TopFieldOrderCnt = f->poc;
2366 pic_param->ReferenceFrames[i].flags =
2367 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2368 pic_param->ReferenceFrames[i].frame_idx = f->frame_num;
2372 pic_param->ReferenceFrames[i].picture_id = VA_INVALID_ID;
2378 _add_picture_parameter (GstVaH264Enc * self, GstVaH264EncFrame * frame,
2379 VAEncPictureParameterBufferH264 * pic_param)
2381 if (!gst_va_encoder_add_param (self->encoder, frame->picture,
2382 VAEncPictureParameterBufferType, pic_param,
2383 sizeof (VAEncPictureParameterBufferH264))) {
2384 GST_ERROR_OBJECT (self, "Failed to create the picture parameter");
2392 _fill_pps (VAEncPictureParameterBufferH264 * pic_param, GstH264SPS * sps,
2396 *pps = (GstH264PPS) {
2399 .entropy_coding_mode_flag =
2400 pic_param->pic_fields.bits.entropy_coding_mode_flag,
2401 .pic_order_present_flag =
2402 pic_param->pic_fields.bits.pic_order_present_flag,
2403 .num_slice_groups_minus1 = 0,
2405 .num_ref_idx_l0_active_minus1 = pic_param->num_ref_idx_l0_active_minus1,
2406 .num_ref_idx_l1_active_minus1 = pic_param->num_ref_idx_l1_active_minus1,
2408 .weighted_pred_flag = pic_param->pic_fields.bits.weighted_pred_flag,
2409 .weighted_bipred_idc = pic_param->pic_fields.bits.weighted_bipred_idc,
2410 .pic_init_qp_minus26 = pic_param->pic_init_qp - 26,
2411 .pic_init_qs_minus26 = 0,
2412 .chroma_qp_index_offset = pic_param->chroma_qp_index_offset,
2413 .deblocking_filter_control_present_flag =
2414 pic_param->pic_fields.bits.deblocking_filter_control_present_flag,
2415 .constrained_intra_pred_flag =
2416 pic_param->pic_fields.bits.constrained_intra_pred_flag,
2417 .redundant_pic_cnt_present_flag =
2418 pic_param->pic_fields.bits.redundant_pic_cnt_present_flag,
2419 .transform_8x8_mode_flag =
2420 pic_param->pic_fields.bits.transform_8x8_mode_flag,
2421 /* unsupport scaling lists */
2422 .pic_scaling_matrix_present_flag = 0,
2423 .second_chroma_qp_index_offset = pic_param->second_chroma_qp_index_offset,
2429 _add_picture_header (GstVaH264Enc * self, GstVaH264EncFrame * frame,
2432 #define PPS_SIZE 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8
2433 guint8 packed_pps[PPS_SIZE] = { 0, };
2437 size = sizeof (packed_pps);
2438 if (gst_h264_bit_writer_pps (pps, TRUE, packed_pps,
2439 &size) != GST_H264_BIT_WRITER_OK) {
2440 GST_ERROR_OBJECT (self, "Failed to generate the picture header");
2444 if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
2445 VAEncPackedHeaderPicture, packed_pps, size, FALSE)) {
2446 GST_ERROR_OBJECT (self, "Failed to add the packed picture header");
2454 _add_one_slice (GstVaH264Enc * self, GstVaH264EncFrame * frame,
2455 gint start_mb, gint mb_size,
2456 VAEncSliceParameterBufferH264 * slice,
2457 GstVaH264EncFrame * list0[16], guint list0_num,
2458 GstVaH264EncFrame * list1[16], guint list1_num)
2460 int8_t slice_qp_delta = 0;
2464 if (self->rc.rc_ctrl_mode == VA_RC_CQP) {
2465 if (frame->type == GST_H264_P_SLICE) {
2466 slice_qp_delta = self->rc.qp_p - self->rc.qp_i;
2467 } else if (frame->type == GST_H264_B_SLICE) {
2468 slice_qp_delta = (int8_t) (self->rc.qp_b - self->rc.qp_i);
2470 g_assert (slice_qp_delta <= 51 && slice_qp_delta >= -51);
2473 *slice = (VAEncSliceParameterBufferH264) {
2474 .macroblock_address = start_mb,
2475 .num_macroblocks = mb_size,
2476 .macroblock_info = VA_INVALID_ID,
2477 .slice_type = (uint8_t) frame->type,
2478 /* Only one parameter set supported now. */
2479 .pic_parameter_set_id = 0,
2480 .idr_pic_id = self->gop.total_idr_count,
2481 .pic_order_cnt_lsb = frame->poc,
2482 /* Not support top/bottom. */
2483 .delta_pic_order_cnt_bottom = 0,
2484 .delta_pic_order_cnt[0] = 0,
2485 .delta_pic_order_cnt[1] = 0,
2487 .direct_spatial_mv_pred_flag = TRUE,
2488 /* .num_ref_idx_active_override_flag = , */
2489 /* .num_ref_idx_l0_active_minus1 = , */
2490 /* .num_ref_idx_l1_active_minus1 = , */
2491 /* Set the reference list later. */
2493 .luma_log2_weight_denom = 0,
2494 .chroma_log2_weight_denom = 0,
2495 .luma_weight_l0_flag = 0,
2496 .chroma_weight_l0_flag = 0,
2497 .luma_weight_l1_flag = 0,
2498 .chroma_weight_l1_flag = 0,
2500 .cabac_init_idc = 0,
2501 /* Just use picture default setting. */
2502 .slice_qp_delta = slice_qp_delta,
2504 .disable_deblocking_filter_idc = 0,
2505 .slice_alpha_c0_offset_div2 = 2,
2506 .slice_beta_offset_div2 = 2,
2510 if (frame->type == GST_H264_B_SLICE || frame->type == GST_H264_P_SLICE) {
2511 slice->num_ref_idx_active_override_flag = (list0_num > 0 || list1_num > 0);
2512 slice->num_ref_idx_l0_active_minus1 = list0_num > 0 ? list0_num - 1 : 0;
2513 if (frame->type == GST_H264_B_SLICE)
2514 slice->num_ref_idx_l1_active_minus1 = list1_num > 0 ? list1_num - 1 : 0;
2518 if (frame->type != GST_H264_I_SLICE) {
2519 for (; i < list0_num; i++) {
2520 slice->RefPicList0[i].picture_id =
2521 gst_va_encode_picture_get_reconstruct_surface (list0[i]->picture);
2522 slice->RefPicList0[i].TopFieldOrderCnt = list0[i]->poc;
2523 slice->RefPicList0[i].flags |= VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2524 slice->RefPicList0[i].frame_idx = list0[i]->frame_num;
2527 for (; i < G_N_ELEMENTS (slice->RefPicList0); ++i) {
2528 slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE;
2529 slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
2533 if (frame->type == GST_H264_B_SLICE) {
2534 for (; i < list1_num; i++) {
2535 slice->RefPicList1[i].picture_id =
2536 gst_va_encode_picture_get_reconstruct_surface (list1[i]->picture);
2537 slice->RefPicList1[i].TopFieldOrderCnt = list1[i]->poc;
2538 slice->RefPicList1[i].flags |= VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2539 slice->RefPicList1[i].frame_idx = list1[i]->frame_num;
2542 for (; i < G_N_ELEMENTS (slice->RefPicList1); ++i) {
2543 slice->RefPicList1[i].picture_id = VA_INVALID_SURFACE;
2544 slice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
2547 if (!gst_va_encoder_add_param (self->encoder, frame->picture,
2548 VAEncSliceParameterBufferType, slice,
2549 sizeof (VAEncSliceParameterBufferH264))) {
2550 GST_ERROR_OBJECT (self, "Failed to create the slice parameter");
2558 _poc_asc_compare (const GstVaH264EncFrame ** a, const GstVaH264EncFrame ** b)
2560 return (*a)->poc - (*b)->poc;
2564 _poc_des_compare (const GstVaH264EncFrame ** a, const GstVaH264EncFrame ** b)
2566 return (*b)->poc - (*a)->poc;
2570 _frame_num_asc_compare (const GstVaH264EncFrame ** a,
2571 const GstVaH264EncFrame ** b)
2573 return (*a)->frame_num - (*b)->frame_num;
2577 _frame_num_des_compare (const GstVaH264EncFrame ** a,
2578 const GstVaH264EncFrame ** b)
2580 return (*b)->frame_num - (*a)->frame_num;
2583 /* If all the pic_num in the same order, OK. */
2585 _ref_list_need_reorder (GstVaH264EncFrame * list[16], guint list_num,
2594 for (i = 1; i < list_num; i++) {
2595 pic_num_diff = list[i]->frame_num - list[i - 1]->frame_num;
2596 g_assert (pic_num_diff != 0);
2598 if (pic_num_diff > 0 && !is_asc)
2601 if (pic_num_diff < 0 && is_asc)
2609 _insert_ref_pic_list_modification (GstH264SliceHdr * slice_hdr,
2610 GstVaH264EncFrame * list[16], guint list_num, gboolean is_asc)
2612 GstVaH264EncFrame *list_by_pic_num[16] = { };
2613 guint modification_num, i;
2614 GstH264RefPicListModification *ref_pic_list_modification = NULL;
2615 gint pic_num_diff, pic_num_lx_pred;
2617 memcpy (list_by_pic_num, list, sizeof (GstVaH264EncFrame *) * list_num);
2620 g_qsort_with_data (list_by_pic_num, list_num, sizeof (gpointer),
2621 (GCompareDataFunc) _frame_num_asc_compare, NULL);
2623 g_qsort_with_data (list_by_pic_num, list_num, sizeof (gpointer),
2624 (GCompareDataFunc) _frame_num_des_compare, NULL);
2627 modification_num = 0;
2628 for (i = 0; i < list_num; i++) {
2629 if (list_by_pic_num[i]->poc != list[i]->poc)
2630 modification_num = i + 1;
2632 g_assert (modification_num > 0);
2635 slice_hdr->ref_pic_list_modification_flag_l1 = 1;
2636 slice_hdr->n_ref_pic_list_modification_l1 =
2637 modification_num + 1 /* The end operation. */ ;
2638 ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l1;
2640 slice_hdr->ref_pic_list_modification_flag_l0 = 1;
2641 slice_hdr->n_ref_pic_list_modification_l0 =
2642 modification_num + 1 /* The end operation. */ ;
2643 ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l0;
2646 pic_num_lx_pred = slice_hdr->frame_num;
2647 for (i = 0; i < modification_num; i++) {
2648 pic_num_diff = list[i]->frame_num - pic_num_lx_pred;
2649 /* For the nex loop. */
2650 pic_num_lx_pred = list[i]->frame_num;
2652 g_assert (pic_num_diff != 0);
2654 if (pic_num_diff > 0) {
2655 ref_pic_list_modification->modification_of_pic_nums_idc = 1;
2656 ref_pic_list_modification->value.abs_diff_pic_num_minus1 =
2659 ref_pic_list_modification->modification_of_pic_nums_idc = 0;
2660 ref_pic_list_modification->value.abs_diff_pic_num_minus1 =
2661 (-pic_num_diff) - 1;
2664 ref_pic_list_modification++;
2667 ref_pic_list_modification->modification_of_pic_nums_idc = 3;
2671 _insert_ref_pic_marking_for_unused_frame (GstH264SliceHdr * slice_hdr,
2672 gint cur_frame_num, gint unused_frame_num)
2674 GstH264RefPicMarking *refpicmarking;
2676 slice_hdr->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag = 1;
2677 slice_hdr->dec_ref_pic_marking.n_ref_pic_marking = 2;
2679 refpicmarking = &slice_hdr->dec_ref_pic_marking.ref_pic_marking[0];
2681 refpicmarking->memory_management_control_operation = 1;
2682 refpicmarking->difference_of_pic_nums_minus1 =
2683 cur_frame_num - unused_frame_num - 1;
2685 refpicmarking = &slice_hdr->dec_ref_pic_marking.ref_pic_marking[1];
2686 refpicmarking->memory_management_control_operation = 0;
2690 _add_slice_header (GstVaH264Enc * self, GstVaH264EncFrame * frame,
2691 GstH264PPS * pps, VAEncSliceParameterBufferH264 * slice,
2692 GstVaH264EncFrame * list0[16], guint list0_num,
2693 GstVaH264EncFrame * list1[16], guint list1_num)
2695 GstH264SliceHdr slice_hdr;
2697 GstH264NalUnitType nal_type = GST_H264_NAL_SLICE;
2698 #define SLICE_HDR_SIZE 4 + GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8
2699 guint8 packed_slice_hdr[SLICE_HDR_SIZE] = { 0, };
2700 #undef SLICE_HDR_SIZE
2702 if (frame->frame_num == 0)
2703 nal_type = GST_H264_NAL_SLICE_IDR;
2706 slice_hdr = (GstH264SliceHdr) {
2707 .first_mb_in_slice = slice->macroblock_address,
2708 .type = slice->slice_type,
2710 .frame_num = frame->frame_num,
2711 /* interlaced not supported now. */
2712 .field_pic_flag = 0,
2713 .bottom_field_flag = 0,
2714 .idr_pic_id = (frame->frame_num == 0 ? slice->idr_pic_id : 0),
2715 /* only pic_order_cnt_type 1 is supported now. */
2716 .pic_order_cnt_lsb = slice->pic_order_cnt_lsb,
2717 .delta_pic_order_cnt_bottom = slice->delta_pic_order_cnt_bottom,
2718 /* Only for B frame. */
2719 .direct_spatial_mv_pred_flag =
2720 (frame->type == GST_H264_B_SLICE ?
2721 slice->direct_spatial_mv_pred_flag : 0),
2723 .num_ref_idx_active_override_flag = slice->num_ref_idx_active_override_flag,
2724 .num_ref_idx_l0_active_minus1 = slice->num_ref_idx_l0_active_minus1,
2725 .num_ref_idx_l1_active_minus1 = slice->num_ref_idx_l1_active_minus1,
2726 /* Calculate it later. */
2727 .ref_pic_list_modification_flag_l0 = 0,
2728 .ref_pic_list_modification_flag_l1 = 0,
2729 /* We have weighted_pred_flag and weighted_bipred_idc 0 here, no
2730 * need weight_table. */
2732 .dec_ref_pic_marking = {
2733 .no_output_of_prior_pics_flag = 0,
2734 .long_term_reference_flag = 0,
2735 /* If not sliding_window, we set it later. */
2736 .adaptive_ref_pic_marking_mode_flag = 0,
2739 .cabac_init_idc = slice->cabac_init_idc,
2740 .slice_qp_delta = slice->slice_qp_delta,
2742 .disable_deblocking_filter_idc = slice->disable_deblocking_filter_idc,
2743 .slice_alpha_c0_offset_div2 = slice->slice_alpha_c0_offset_div2,
2744 .slice_beta_offset_div2 = slice->slice_beta_offset_div2,
2748 /* Reorder the ref lists if needed. */
2749 if (list0_num > 1) {
2750 /* list0 is in poc descend order now. */
2751 if (_ref_list_need_reorder (list0, list0_num, FALSE))
2752 _insert_ref_pic_list_modification (&slice_hdr, list0, list0_num, FALSE);
2755 if (list0_num > 1) {
2756 /* list0 is in poc ascend order now. */
2757 if (_ref_list_need_reorder (list1, list1_num, TRUE)) {
2758 _insert_ref_pic_list_modification (&slice_hdr, list1, list1_num, TRUE);
2762 /* Mark the unused reference explicitly which this frame replaces. */
2763 if (frame->unused_for_reference_pic_num >= 0) {
2764 g_assert (frame->is_ref);
2765 _insert_ref_pic_marking_for_unused_frame (&slice_hdr, frame->frame_num,
2766 frame->unused_for_reference_pic_num);
2769 size = sizeof (packed_slice_hdr);
2770 if (gst_h264_bit_writer_slice_hdr (&slice_hdr, TRUE, nal_type, frame->is_ref,
2771 packed_slice_hdr, &size) != GST_H264_BIT_WRITER_OK) {
2772 GST_ERROR_OBJECT (self, "Failed to generate the slice header");
2776 if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
2777 VAEncPackedHeaderSlice, packed_slice_hdr, size, FALSE)) {
2778 GST_ERROR_OBJECT (self, "Failed to add the packed slice header");
2786 _add_aud (GstVaH264Enc * self, GstVaH264EncFrame * frame)
2788 guint8 aud_data[8] = { };
2790 guint8 primary_pic_type = 0;
2792 switch (frame->type) {
2793 case GST_H264_I_SLICE:
2794 primary_pic_type = 0;
2796 case GST_H264_P_SLICE:
2797 primary_pic_type = 1;
2799 case GST_H264_B_SLICE:
2800 primary_pic_type = 2;
2803 g_assert_not_reached ();
2807 size = sizeof (aud_data);
2808 if (gst_h264_bit_writer_aud (primary_pic_type, TRUE, aud_data,
2809 &size) != GST_H264_BIT_WRITER_OK) {
2810 GST_ERROR_OBJECT (self, "Failed to generate the AUD");
2814 if (!gst_va_encoder_add_packed_header (self->encoder, frame->picture,
2815 VAEncPackedHeaderRawData, aud_data, size, FALSE)) {
2816 GST_ERROR_OBJECT (self, "Failed to add the AUD");
2824 gst_va_h264_enc_encode_frame (GstVaH264Enc * self,
2825 GstVideoCodecFrame * gst_frame)
2827 VAEncPictureParameterBufferH264 pic_param;
2829 GstVaH264EncFrame *list0[16] = { NULL, };
2830 guint list0_num = 0;
2831 GstVaH264EncFrame *list1[16] = { NULL, };
2832 guint list1_num = 0;
2833 guint slice_of_mbs, slice_mod_mbs, slice_start_mb, slice_mbs;
2835 GstVaH264EncFrame *frame;
2837 g_return_val_if_fail (gst_frame, FALSE);
2839 frame = _enc_frame (gst_frame);
2841 /* Repeat the SPS for IDR. */
2842 if (frame->poc == 0) {
2843 VAEncSequenceParameterBufferH264 sequence;
2845 if (!_add_rate_control_parameter (self, frame->picture))
2848 if (!_add_quality_level_parameter (self, frame->picture))
2851 if (!_add_frame_rate_parameter (self, frame->picture))
2854 if (!_add_hrd_parameter (self, frame->picture))
2857 if (!_add_trellis_parameter (self, frame->picture))
2860 _fill_sequence_param (self, &sequence);
2861 if (!_fill_sps (self, &sequence))
2864 if (!_add_sequence_parameter (self, frame->picture, &sequence))
2867 if ((self->packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE)
2868 && !_add_sequence_header (self, frame))
2872 if (self->prop.aud) {
2873 if ((self->packed_headers & VA_ENC_PACKED_HEADER_RAW_DATA)
2874 && !_add_aud (self, frame))
2878 /* Non I frame, construct reference list. */
2879 if (frame->type != GST_H264_I_SLICE) {
2880 GstVaH264EncFrame *vaf;
2881 GstVideoCodecFrame *f;
2883 for (i = g_queue_get_length (&self->ref_list) - 1; i >= 0; i--) {
2884 f = g_queue_peek_nth (&self->ref_list, i);
2885 vaf = _enc_frame (f);
2886 if (vaf->poc > frame->poc)
2889 list0[list0_num] = vaf;
2893 /* reorder to select the most nearest forward frames. */
2894 g_qsort_with_data (list0, list0_num, sizeof (gpointer),
2895 (GCompareDataFunc) _poc_des_compare, NULL);
2897 if (list0_num > self->gop.ref_num_list0)
2898 list0_num = self->gop.ref_num_list0;
2901 if (frame->type == GST_H264_B_SLICE) {
2902 GstVaH264EncFrame *vaf;
2903 GstVideoCodecFrame *f;
2905 for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
2906 f = g_queue_peek_nth (&self->ref_list, i);
2907 vaf = _enc_frame (f);
2908 if (vaf->poc < frame->poc)
2911 list1[list1_num] = vaf;
2915 /* reorder to select the most nearest backward frames. */
2916 g_qsort_with_data (list1, list1_num, sizeof (gpointer),
2917 (GCompareDataFunc) _poc_asc_compare, NULL);
2919 if (list1_num > self->gop.ref_num_list1)
2920 list1_num = self->gop.ref_num_list1;
2923 g_assert (list0_num + list1_num <= self->gop.num_ref_frames);
2925 if (!_fill_picture_parameter (self, frame, &pic_param))
2927 if (!_add_picture_parameter (self, frame, &pic_param))
2929 _fill_pps (&pic_param, &self->sequence_hdr, &pps);
2931 if ((self->packed_headers & VA_ENC_PACKED_HEADER_PICTURE)
2932 && frame->type == GST_H264_I_SLICE
2933 && !_add_picture_header (self, frame, &pps))
2936 slice_of_mbs = self->mb_width * self->mb_height / self->num_slices;
2937 slice_mod_mbs = self->mb_width * self->mb_height % self->num_slices;
2940 for (i = 0; i < self->num_slices; i++) {
2941 VAEncSliceParameterBufferH264 slice;
2943 slice_mbs = slice_of_mbs;
2944 /* divide the remainder to each equally */
2945 if (slice_mod_mbs) {
2950 if (!_add_one_slice (self, frame, slice_start_mb, slice_mbs, &slice,
2951 list0, list0_num, list1, list1_num))
2954 if ((self->packed_headers & VA_ENC_PACKED_HEADER_SLICE) &&
2955 (!_add_slice_header (self, frame, &pps, &slice, list0, list0_num, list1,
2959 slice_start_mb += slice_mbs;
2962 if (!gst_va_encoder_encode (self->encoder, frame->picture)) {
2963 GST_ERROR_OBJECT (self, "Encode frame error");
2971 gst_va_h264_enc_start (GstVideoEncoder * encoder)
2973 GstVaH264Enc *self = GST_VA_H264_ENC (encoder);
2975 /* Set the minimum pts to some huge value (1000 hours). This keeps
2976 * the dts at the start of the stream from needing to be
2978 self->start_pts = GST_SECOND * 60 * 60 * 1000;
2979 gst_video_encoder_set_min_pts (encoder, self->start_pts);
2985 gst_va_h264_enc_open (GstVideoEncoder * venc)
2987 GstVaH264Enc *encoder = GST_VA_H264_ENC (venc);
2988 GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (venc);
2989 gboolean ret = FALSE;
2991 if (!gst_va_ensure_element_data (venc, klass->render_device_path,
2995 if (!g_atomic_pointer_get (&encoder->encoder)) {
2996 GstVaEncoder *va_encoder;
2998 va_encoder = gst_va_encoder_new (encoder->display, klass->codec);
3002 gst_object_replace ((GstObject **) (&encoder->encoder),
3003 (GstObject *) va_encoder);
3004 gst_clear_object (&va_encoder);
3013 gst_va_h264_enc_close (GstVideoEncoder * venc)
3015 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3017 gst_va_h264_enc_reset_state (self);
3019 gst_clear_object (&self->encoder);
3020 gst_clear_object (&self->display);
3026 gst_va_h264_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter)
3028 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3029 GstCaps *caps = NULL, *tmp;
3032 caps = gst_va_encoder_get_sinkpad_caps (self->encoder);
3036 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
3037 gst_caps_unref (caps);
3041 caps = gst_video_encoder_proxy_getcaps (venc, NULL, filter);
3044 GST_LOG_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, caps);
3049 _flush_all_frames (GstVideoEncoder * venc)
3051 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3053 g_queue_clear_full (&self->reorder_list,
3054 (GDestroyNotify) gst_video_codec_frame_unref);
3055 g_queue_clear_full (&self->output_list,
3056 (GDestroyNotify) gst_video_codec_frame_unref);
3057 g_queue_clear_full (&self->ref_list,
3058 (GDestroyNotify) gst_video_codec_frame_unref);
3062 gst_va_h264_enc_flush (GstVideoEncoder * venc)
3064 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3066 _flush_all_frames (venc);
3068 /* begin from an IDR after flush. */
3069 self->gop.cur_frame_index = 0;
3070 self->gop.cur_frame_num = 0;
3076 gst_va_h264_enc_stop (GstVideoEncoder * venc)
3078 GstVaH264Enc *const self = GST_VA_H264_ENC (venc);
3080 _flush_all_frames (venc);
3082 if (!gst_va_encoder_close (self->encoder)) {
3083 GST_ERROR_OBJECT (self, "Failed to close the VA encoder");
3088 gst_buffer_pool_set_active (self->raw_pool, FALSE);
3089 gst_clear_object (&self->raw_pool);
3091 if (self->input_state)
3092 gst_video_codec_state_unref (self->input_state);
3093 self->input_state = NULL;
3094 if (self->output_state)
3095 gst_video_codec_state_unref (self->output_state);
3096 self->output_state = NULL;
3098 gst_clear_caps (&self->in_caps);
3104 _try_import_buffer (GstVaH264Enc * self, GstBuffer * inbuf)
3106 VASurfaceID surface;
3108 /* The VA buffer. */
3109 surface = gst_va_buffer_get_surface (inbuf);
3110 if (surface != VA_INVALID_ID)
3113 /* TODO: DMA buffer. */
3118 static GstBufferPool *
3119 _get_sinkpad_pool (GstVaH264Enc * self)
3121 GstAllocator *allocator;
3122 GstAllocationParams params = { 0, };
3123 guint size, usage_hint = 0;
3124 GArray *surface_formats = NULL;
3128 return self->raw_pool;
3130 g_assert (self->in_caps);
3131 caps = gst_caps_copy (self->in_caps);
3132 gst_caps_set_features_simple (caps,
3133 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
3135 gst_allocation_params_init (¶ms);
3137 size = GST_VIDEO_INFO_SIZE (&self->in_info);
3139 surface_formats = gst_va_encoder_get_surface_formats (self->encoder);
3141 allocator = gst_va_allocator_new (self->display, surface_formats);
3143 self->raw_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
3144 usage_hint, GST_VA_FEATURE_AUTO, allocator, ¶ms);
3145 if (!self->raw_pool) {
3146 gst_object_unref (allocator);
3150 gst_va_allocator_get_format (allocator, &self->sinkpad_info, NULL, NULL);
3152 gst_object_unref (allocator);
3154 gst_buffer_pool_set_active (self->raw_pool, TRUE);
3156 return self->raw_pool;
3159 static GstFlowReturn
3160 _import_input_buffer (GstVaH264Enc * self, GstBuffer * inbuf, GstBuffer ** buf)
3162 GstBuffer *buffer = NULL;
3163 GstBufferPool *pool;
3165 GstVideoFrame in_frame, out_frame;
3166 gboolean imported, copied;
3168 imported = _try_import_buffer (self, inbuf);
3170 *buf = gst_buffer_ref (inbuf);
3174 /* input buffer doesn't come from a vapool, thus it is required to
3175 * have a pool, grab from it a new buffer and copy the input
3176 * buffer to the new one */
3177 if (!(pool = _get_sinkpad_pool (self)))
3178 return GST_FLOW_ERROR;
3180 ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
3181 if (ret != GST_FLOW_OK)
3184 GST_LOG_OBJECT (self, "copying input frame");
3186 if (!gst_video_frame_map (&in_frame, &self->in_info, inbuf, GST_MAP_READ))
3187 goto invalid_buffer;
3188 if (!gst_video_frame_map (&out_frame, &self->sinkpad_info, buffer,
3190 gst_video_frame_unmap (&in_frame);
3191 goto invalid_buffer;
3194 copied = gst_video_frame_copy (&out_frame, &in_frame);
3196 gst_video_frame_unmap (&out_frame);
3197 gst_video_frame_unmap (&in_frame);
3200 goto invalid_buffer;
3202 /* strictly speaking this is not needed but let's play safe */
3203 if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
3204 GST_BUFFER_COPY_TIMESTAMPS, 0, -1))
3205 return GST_FLOW_ERROR;
3213 GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL),
3214 ("invalid video buffer received"));
3216 gst_buffer_unref (buffer);
3217 return GST_FLOW_ERROR;
3221 static GstFlowReturn
3222 _push_buffer_to_downstream (GstVaH264Enc * self, GstVideoCodecFrame * frame)
3224 GstVaH264EncFrame *frame_enc;
3230 VASurfaceID surface;
3232 VACodedBufferSegment *seg, *seg_list;
3234 dpy = gst_va_display_get_va_dpy (self->display);
3236 frame_enc = _enc_frame (frame);
3238 /* Wait for encoding to finish */
3239 surface = gst_va_encode_picture_get_raw_surface (frame_enc->picture);
3240 status = vaSyncSurface (dpy, surface);
3241 if (status != VA_STATUS_SUCCESS) {
3242 GST_WARNING_OBJECT (self, "vaSyncSurface: %s", vaErrorStr (status));
3247 status = vaMapBuffer (dpy, frame_enc->picture->coded_buffer,
3248 (gpointer *) & seg_list);
3249 if (status != VA_STATUS_SUCCESS) {
3250 GST_WARNING_OBJECT (self, "vaMapBuffer: %s", vaErrorStr (status));
3255 GST_WARNING_OBJECT (self, "coded buffer has no segment list");
3260 for (seg = seg_list; seg; seg = seg->next)
3261 coded_size += seg->size;
3263 buf = gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (self),
3266 GST_ERROR_OBJECT (self, "Failed to allocate output buffer, size %d",
3272 for (seg = seg_list; seg; seg = seg->next) {
3275 write_size = gst_buffer_fill (buf, offset, seg->buf, seg->size);
3276 if (write_size != seg->size) {
3277 GST_WARNING_OBJECT (self, "Segment size is %d, but copied %"
3278 G_GSIZE_FORMAT, seg->size, write_size);
3281 offset += seg->size;
3284 status = vaUnmapBuffer (dpy, frame_enc->picture->coded_buffer);
3285 if (status != VA_STATUS_SUCCESS)
3286 GST_WARNING ("vaUnmapBuffer: %s", vaErrorStr (status));
3289 self->start_pts + self->frame_duration * frame_enc->total_frame_count;
3290 /* The PTS should always be later than the DTS. */
3291 frame->dts = self->start_pts + self->frame_duration *
3292 ((gint64) self->output_frame_count -
3293 (gint64) self->gop.num_reorder_frames);
3294 self->output_frame_count++;
3295 frame->duration = self->frame_duration;
3297 gst_buffer_replace (&frame->output_buffer, buf);
3298 gst_clear_buffer (&buf);
3300 GST_LOG_OBJECT (self, "Push to downstream: frame system_frame_number: %d,"
3301 " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
3302 " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
3303 frame->system_frame_number, GST_TIME_ARGS (frame->pts),
3304 GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
3305 gst_buffer_get_size (frame->output_buffer));
3307 ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
3311 gst_clear_buffer (&frame->output_buffer);
3312 gst_clear_buffer (&buf);
3313 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
3315 return GST_FLOW_ERROR;
3319 _reorder_frame (GstVideoEncoder * venc, GstVideoCodecFrame * frame,
3320 gboolean bump_all, GstVideoCodecFrame ** out_frame)
3322 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3323 GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
3325 g_assert (klass->push_frame);
3326 if (!klass->push_frame (self, frame, bump_all)) {
3327 GST_ERROR_OBJECT (self, "Failed to push the input frame"
3328 " system_frame_number: %d into the reorder list",
3329 frame->system_frame_number);
3335 g_assert (klass->pop_frame);
3336 if (!klass->pop_frame (self, out_frame)) {
3337 GST_ERROR_OBJECT (self, "Failed to pop the frame from the reorder list");
3346 _sort_by_frame_num (gconstpointer a, gconstpointer b, gpointer user_data)
3348 GstVaH264EncFrame *frame1 = _enc_frame ((GstVideoCodecFrame *) a);
3349 GstVaH264EncFrame *frame2 = _enc_frame ((GstVideoCodecFrame *) b);
3351 g_assert (frame1->frame_num != frame2->frame_num);
3353 return frame1->frame_num - frame2->frame_num;
3356 static GstVideoCodecFrame *
3357 _find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
3359 GstVaH264EncFrame *b_vaframe;
3360 GstVideoCodecFrame *b_frame;
3363 /* We still have more space. */
3364 if (g_queue_get_length (&self->ref_list) < self->gop.num_ref_frames)
3367 /* Not b_pyramid, sliding window is enough. */
3368 if (!self->gop.b_pyramid)
3369 return g_queue_peek_head (&self->ref_list);
3371 /* I/P frame, just using sliding window. */
3372 if (frame->type != GST_H264_B_SLICE)
3373 return g_queue_peek_head (&self->ref_list);
3375 /* Choose the B frame with lowest POC. */
3378 for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
3379 GstVaH264EncFrame *vaf;
3380 GstVideoCodecFrame *f;
3382 f = g_queue_peek_nth (&self->ref_list, i);
3383 vaf = _enc_frame (f);
3384 if (vaf->type != GST_H264_B_SLICE)
3389 b_vaframe = _enc_frame (b_frame);
3393 b_vaframe = _enc_frame (b_frame);
3394 g_assert (vaf->poc != b_vaframe->poc);
3395 if (vaf->poc < b_vaframe->poc) {
3397 b_vaframe = _enc_frame (b_frame);
3401 /* No B frame as ref. */
3403 return g_queue_peek_head (&self->ref_list);
3405 if (b_frame != g_queue_peek_head (&self->ref_list)) {
3406 b_vaframe = _enc_frame (b_frame);
3407 frame->unused_for_reference_pic_num = b_vaframe->frame_num;
3408 GST_LOG_OBJECT (self, "The frame with POC: %d, pic_num %d will be"
3409 " replaced by the frame with POC: %d, pic_num %d explicitly by"
3410 " using memory_management_control_operation=1",
3411 b_vaframe->poc, b_vaframe->frame_num, frame->poc, frame->frame_num);
3417 static GstFlowReturn
3418 _encode_frame (GstVideoEncoder * venc, GstVideoCodecFrame * gst_frame)
3420 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3421 GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
3422 GstVaH264EncFrame *frame;
3423 GstVideoCodecFrame *unused_ref = NULL;
3425 frame = _enc_frame (gst_frame);
3426 g_assert (frame->picture == NULL);
3427 frame->picture = gst_va_encode_picture_new (self->encoder,
3428 gst_frame->input_buffer);
3430 if (!frame->picture) {
3431 GST_ERROR_OBJECT (venc, "Failed to create the encode picture");
3432 return GST_FLOW_ERROR;
3436 unused_ref = _find_unused_reference_frame (self, frame);
3438 if (!klass->encode_frame (self, gst_frame)) {
3439 GST_ERROR_OBJECT (venc, "Failed to encode the frame");
3440 return GST_FLOW_ERROR;
3443 g_queue_push_tail (&self->output_list, gst_video_codec_frame_ref (gst_frame));
3445 if (frame->is_ref) {
3447 if (!g_queue_remove (&self->ref_list, unused_ref))
3448 g_assert_not_reached ();
3450 gst_video_codec_frame_unref (unused_ref);
3453 /* Add it into the reference list. */
3454 g_queue_push_tail (&self->ref_list, gst_video_codec_frame_ref (gst_frame));
3455 g_queue_sort (&self->ref_list, _sort_by_frame_num, NULL);
3457 g_assert (g_queue_get_length (&self->ref_list) <= self->gop.num_ref_frames);
3463 static GstFlowReturn
3464 gst_va_h264_enc_handle_frame (GstVideoEncoder * venc,
3465 GstVideoCodecFrame * frame)
3467 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3469 GstBuffer *in_buf = NULL;
3470 GstVaH264EncFrame *frame_in = NULL;
3471 GstVideoCodecFrame *frame_out, *frame_encode = NULL;
3473 GST_LOG_OBJECT (venc,
3474 "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
3475 frame->system_frame_number,
3476 GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
3477 GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
3479 ret = _import_input_buffer (self, frame->input_buffer, &in_buf);
3480 if (ret != GST_FLOW_OK)
3481 goto error_buffer_invalid;
3483 gst_buffer_replace (&frame->input_buffer, in_buf);
3484 gst_clear_buffer (&in_buf);
3486 frame_in = gst_va_enc_frame_new ();
3487 frame_in->total_frame_count = self->input_frame_count++;
3488 gst_video_codec_frame_set_user_data (frame, frame_in, gst_va_enc_frame_free);
3490 if (!_reorder_frame (venc, frame, FALSE, &frame_encode))
3493 /* pass it to reorder list and we should not use it again. */
3496 while (frame_encode) {
3497 ret = _encode_frame (venc, frame_encode);
3498 if (ret != GST_FLOW_OK)
3501 while (g_queue_get_length (&self->output_list) > 0) {
3502 frame_out = g_queue_pop_head (&self->output_list);
3503 gst_video_codec_frame_unref (frame_out);
3504 ret = _push_buffer_to_downstream (self, frame_out);
3505 if (ret != GST_FLOW_OK)
3506 goto error_push_buffer;
3509 frame_encode = NULL;
3510 if (!_reorder_frame (venc, NULL, FALSE, &frame_encode))
3516 error_buffer_invalid:
3518 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
3519 ("Failed to import the input frame."), (NULL));
3520 gst_clear_buffer (&in_buf);
3521 gst_clear_buffer (&frame->output_buffer);
3522 gst_video_encoder_finish_frame (venc, frame);
3527 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
3528 ("Failed to reorder the input frame."), (NULL));
3530 gst_clear_buffer (&frame->output_buffer);
3531 gst_video_encoder_finish_frame (venc, frame);
3533 return GST_FLOW_ERROR;
3537 GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
3538 ("Failed to encode the frame."), (NULL));
3539 gst_clear_buffer (&frame_encode->output_buffer);
3540 gst_video_encoder_finish_frame (venc, frame_encode);
3544 GST_ERROR_OBJECT (self, "Failed to push the buffer");
3548 static GstFlowReturn
3549 gst_va_h264_enc_drain (GstVideoEncoder * venc)
3551 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3552 GstFlowReturn ret = GST_FLOW_OK;
3553 GstVideoCodecFrame *frame_enc = NULL;
3555 GST_DEBUG_OBJECT (self, "Encoder is draining");
3557 /* Kickout all cached frames */
3558 if (!_reorder_frame (venc, NULL, TRUE, &frame_enc)) {
3559 ret = GST_FLOW_ERROR;
3560 goto error_and_purge_all;
3564 if (g_queue_is_empty (&self->reorder_list))
3565 _enc_frame (frame_enc)->last_frame = TRUE;
3567 ret = _encode_frame (venc, frame_enc);
3568 if (ret != GST_FLOW_OK)
3569 goto error_and_purge_all;
3571 frame_enc = g_queue_pop_head (&self->output_list);
3572 gst_video_codec_frame_unref (frame_enc);
3573 ret = _push_buffer_to_downstream (self, frame_enc);
3575 if (ret != GST_FLOW_OK)
3576 goto error_and_purge_all;
3579 if (!_reorder_frame (venc, NULL, TRUE, &frame_enc)) {
3580 ret = GST_FLOW_ERROR;
3581 goto error_and_purge_all;
3585 g_assert (g_queue_is_empty (&self->reorder_list));
3587 /* Output all frames. */
3588 while (!g_queue_is_empty (&self->output_list)) {
3589 frame_enc = g_queue_pop_head (&self->output_list);
3590 gst_video_codec_frame_unref (frame_enc);
3591 ret = _push_buffer_to_downstream (self, frame_enc);
3593 if (ret != GST_FLOW_OK)
3594 goto error_and_purge_all;
3597 /* Also clear the reference list. */
3598 g_queue_clear_full (&self->ref_list,
3599 (GDestroyNotify) gst_video_codec_frame_unref);
3603 error_and_purge_all:
3605 gst_clear_buffer (&frame_enc->output_buffer);
3606 gst_video_encoder_finish_frame (venc, frame_enc);
3609 if (!g_queue_is_empty (&self->output_list)) {
3610 GST_WARNING_OBJECT (self, "Still %d frame in the output list"
3611 " after drain", g_queue_get_length (&self->output_list));
3612 while (!g_queue_is_empty (&self->output_list)) {
3613 frame_enc = g_queue_pop_head (&self->output_list);
3614 gst_video_codec_frame_unref (frame_enc);
3615 gst_clear_buffer (&frame_enc->output_buffer);
3616 gst_video_encoder_finish_frame (venc, frame_enc);
3620 if (!g_queue_is_empty (&self->reorder_list)) {
3621 GST_WARNING_OBJECT (self, "Still %d frame in the reorder list"
3622 " after drain", g_queue_get_length (&self->reorder_list));
3623 while (!g_queue_is_empty (&self->reorder_list)) {
3624 frame_enc = g_queue_pop_head (&self->reorder_list);
3625 gst_video_codec_frame_unref (frame_enc);
3626 gst_clear_buffer (&frame_enc->output_buffer);
3627 gst_video_encoder_finish_frame (venc, frame_enc);
3631 /* Also clear the reference list. */
3632 g_queue_clear_full (&self->ref_list,
3633 (GDestroyNotify) gst_video_codec_frame_unref);
3638 static GstFlowReturn
3639 gst_va_h264_enc_finish (GstVideoEncoder * venc)
3641 return gst_va_h264_enc_drain (venc);
3644 static GstAllocator *
3645 _allocator_from_caps (GstVaH264Enc * self, GstCaps * caps)
3647 GstAllocator *allocator = NULL;
3649 if (gst_caps_is_dmabuf (caps)) {
3650 allocator = gst_va_dmabuf_allocator_new (self->display);
3652 GArray *surface_formats =
3653 gst_va_encoder_get_surface_formats (self->encoder);
3654 allocator = gst_va_allocator_new (self->display, surface_formats);
3661 gst_va_h264_enc_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
3663 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3664 GstAllocator *allocator = NULL;
3665 GstAllocationParams params = { 0, };
3666 GstBufferPool *pool;
3669 gboolean need_pool = FALSE;
3670 guint size, usage_hint = 0;
3672 gst_query_parse_allocation (query, &caps, &need_pool);
3676 if (!gst_video_info_from_caps (&info, caps)) {
3677 GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, caps);
3681 size = GST_VIDEO_INFO_SIZE (&info);
3683 gst_allocation_params_init (¶ms);
3685 if (!(allocator = _allocator_from_caps (self, caps)))
3688 pool = gst_va_pool_new_with_config (caps, size, 1, 0, usage_hint,
3689 GST_VA_FEATURE_AUTO, allocator, ¶ms);
3691 gst_object_unref (allocator);
3695 gst_query_add_allocation_param (query, allocator, ¶ms);
3696 gst_query_add_allocation_pool (query, pool, size, 0, 0);
3698 GST_DEBUG_OBJECT (self,
3699 "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
3702 gst_object_unref (allocator);
3703 gst_object_unref (pool);
3705 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
3712 GST_ERROR_OBJECT (self, "failed to set config");
3718 gst_va_h264_enc_set_context (GstElement * element, GstContext * context)
3720 GstVaDisplay *old_display, *new_display;
3721 GstVaH264Enc *self = GST_VA_H264_ENC (element);
3722 GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
3725 old_display = self->display ? gst_object_ref (self->display) : NULL;
3727 ret = gst_va_handle_set_context (element, context, klass->render_device_path,
3730 new_display = self->display ? gst_object_ref (self->display) : NULL;
3732 if (!ret || (old_display && new_display && old_display != new_display
3733 && self->encoder)) {
3734 GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
3735 ("Can't replace VA display while operating"), (NULL));
3738 gst_clear_object (&old_display);
3739 gst_clear_object (&new_display);
3741 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
3745 gst_va_h264_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
3747 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3748 GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
3750 guint max_ref_frames;
3752 g_return_val_if_fail (state->caps != NULL, FALSE);
3754 if (self->input_state)
3755 gst_video_codec_state_unref (self->input_state);
3756 self->input_state = gst_video_codec_state_ref (state);
3758 gst_caps_replace (&self->in_caps, state->caps);
3760 if (!gst_video_info_from_caps (&self->in_info, self->in_caps))
3763 if (gst_va_h264_enc_drain (venc) != GST_FLOW_OK)
3766 if (!gst_va_encoder_close (self->encoder)) {
3767 GST_ERROR_OBJECT (self, "Failed to close the VA encoder");
3771 g_assert (klass->reconfig);
3772 if (!klass->reconfig (self)) {
3773 GST_ERROR_OBJECT (self, "Reconfig the encoder error");
3777 max_ref_frames = self->gop.num_ref_frames + 3 /* scratch frames */ ;
3778 if (!gst_va_encoder_open (self->encoder, self->profile, self->entrypoint,
3779 GST_VIDEO_INFO_FORMAT (&self->in_info), self->rt_format,
3780 self->mb_width * 16, self->mb_height * 16, self->codedbuf_size,
3781 max_ref_frames, self->rc.rc_ctrl_mode, self->packed_headers)) {
3782 GST_ERROR_OBJECT (self, "Failed to open the VA encoder.");
3788 GstTagList *tags = gst_tag_list_new_empty ();
3789 const gchar *encoder_name;
3792 g_object_get (venc, "bitrate", &bitrate, NULL);
3794 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
3798 gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
3799 GST_ELEMENT_METADATA_LONGNAME)))
3800 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
3801 encoder_name, NULL);
3803 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, "H264", NULL);
3805 gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
3806 gst_tag_list_unref (tags);
3809 out_caps = gst_va_profile_caps (self->profile);
3810 g_assert (out_caps);
3811 out_caps = gst_caps_fixate (out_caps);
3813 if (self->level_str)
3814 gst_caps_set_simple (out_caps, "level", G_TYPE_STRING, self->level_str,
3817 gst_caps_set_simple (out_caps, "width", G_TYPE_INT, self->width,
3818 "height", G_TYPE_INT, self->height, "alignment", G_TYPE_STRING, "au",
3819 "stream-format", G_TYPE_STRING, "byte-stream", NULL);
3821 GST_DEBUG_OBJECT (self, "output caps is %" GST_PTR_FORMAT, out_caps);
3823 if (self->output_state)
3824 gst_video_codec_state_unref (self->output_state);
3825 self->output_state = gst_video_encoder_set_output_state (venc, out_caps,
3828 if (!gst_video_encoder_negotiate (venc)) {
3829 GST_ERROR_OBJECT (self, "Failed to negotiate with the downstream");
3837 _query_context (GstVaH264Enc * self, GstQuery * query)
3839 GstVaDisplay *display = NULL;
3842 gst_object_replace ((GstObject **) & display, (GstObject *) self->display);
3843 ret = gst_va_handle_context_query (GST_ELEMENT_CAST (self), query, display);
3844 gst_clear_object (&display);
3850 gst_va_h264_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
3852 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3853 gboolean ret = FALSE;
3855 switch (GST_QUERY_TYPE (query)) {
3856 case GST_QUERY_CONTEXT:{
3857 ret = _query_context (self, query);
3860 case GST_QUERY_CAPS:{
3861 GstCaps *caps = NULL, *tmp, *filter = NULL;
3862 GstVaEncoder *va_encoder = NULL;
3863 gboolean fixed_caps;
3865 gst_object_replace ((GstObject **) & va_encoder,
3866 (GstObject *) self->encoder);
3868 gst_query_parse_caps (query, &filter);
3870 fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
3872 if (!fixed_caps && va_encoder)
3873 caps = gst_va_encoder_get_srcpad_caps (va_encoder);
3875 gst_clear_object (&va_encoder);
3879 tmp = gst_caps_intersect_full (filter, caps,
3880 GST_CAPS_INTERSECT_FIRST);
3881 gst_caps_unref (caps);
3885 GST_LOG_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, caps);
3886 gst_query_set_caps_result (query, caps);
3887 gst_caps_unref (caps);
3891 /* else jump to default */
3894 ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
3902 gst_va_h264_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
3904 GstVaH264Enc *self = GST_VA_H264_ENC (venc);
3906 if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
3907 return _query_context (self, query);
3909 return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
3913 static const gchar *sink_caps_str =
3914 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
3916 GST_VIDEO_CAPS_MAKE ("{ NV12 }");
3919 static const gchar *src_caps_str = "video/x-h264";
3922 _register_debug_category (gpointer data)
3924 GST_DEBUG_CATEGORY_INIT (gst_va_h264enc_debug, "vah264enc", 0,
3931 gst_va_h264_enc_init (GTypeInstance * instance, gpointer g_class)
3933 GstVaH264Enc *self = GST_VA_H264_ENC (instance);
3935 g_queue_init (&self->reorder_list);
3936 g_queue_init (&self->ref_list);
3937 g_queue_init (&self->output_list);
3939 /* default values */
3940 self->prop.key_int_max = 0;
3941 self->prop.num_bframes = 0;
3942 self->prop.num_iframes = 0;
3943 self->prop.num_ref_frames = 3;
3944 self->prop.b_pyramid = FALSE;
3945 self->prop.num_slices = 1;
3946 self->prop.min_qp = 1;
3947 self->prop.max_qp = 51;
3948 self->prop.qp_i = 26;
3949 self->prop.qp_p = 26;
3950 self->prop.qp_b = 26;
3951 self->prop.use_dct8x8 = TRUE;
3952 self->prop.use_cabac = TRUE;
3953 self->prop.use_trellis = FALSE;
3954 self->prop.aud = FALSE;
3955 self->prop.mbbrc = 0;
3956 self->prop.bitrate = 0;
3957 self->prop.target_percentage = 66;
3958 self->prop.target_usage = 4;
3959 self->prop.rc_ctrl = VA_RC_CBR;
3960 self->prop.cpb_size = 0;
3964 gst_va_h264_enc_set_property (GObject * object, guint prop_id,
3965 const GValue * value, GParamSpec * pspec)
3967 GstVaH264Enc *const self = GST_VA_H264_ENC (object);
3969 if (self->encoder && gst_va_encoder_is_open (self->encoder)) {
3970 GST_ERROR_OBJECT (object,
3971 "failed to set any property after encoding started");
3975 GST_OBJECT_LOCK (self);
3978 case PROP_KEY_INT_MAX:
3979 self->prop.key_int_max = g_value_get_uint (value);
3982 self->prop.num_bframes = g_value_get_uint (value);
3985 self->prop.num_iframes = g_value_get_uint (value);
3987 case PROP_NUM_REF_FRAMES:
3988 self->prop.num_ref_frames = g_value_get_uint (value);
3990 case PROP_B_PYRAMID:
3991 self->prop.b_pyramid = g_value_get_boolean (value);
3993 case PROP_NUM_SLICES:
3994 self->prop.num_slices = g_value_get_uint (value);
3997 self->prop.min_qp = g_value_get_uint (value);
4000 self->prop.max_qp = g_value_get_uint (value);
4003 self->prop.qp_i = g_value_get_uint (value);
4006 self->prop.qp_p = g_value_get_uint (value);
4009 self->prop.qp_b = g_value_get_uint (value);
4012 self->prop.use_dct8x8 = g_value_get_boolean (value);
4015 self->prop.use_cabac = g_value_get_boolean (value);
4018 self->prop.use_trellis = g_value_get_boolean (value);
4021 self->prop.aud = g_value_get_boolean (value);
4024 self->prop.mbbrc = g_value_get_enum (value);
4027 self->prop.bitrate = g_value_get_uint (value);
4029 case PROP_TARGET_PERCENTAGE:
4030 self->prop.target_percentage = g_value_get_uint (value);
4032 case PROP_TARGET_USAGE:
4033 self->prop.target_usage = g_value_get_uint (value);
4035 case PROP_RATE_CONTROL:
4036 self->prop.rc_ctrl = g_value_get_enum (value);
4039 self->prop.cpb_size = g_value_get_uint (value);
4042 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4045 GST_OBJECT_UNLOCK (self);
4049 gst_va_h264_enc_get_property (GObject * object, guint prop_id,
4050 GValue * value, GParamSpec * pspec)
4052 GstVaH264Enc *const self = GST_VA_H264_ENC (object);
4054 GST_OBJECT_LOCK (self);
4057 case PROP_KEY_INT_MAX:
4058 g_value_set_uint (value, self->prop.key_int_max);
4061 g_value_set_uint (value, self->prop.num_bframes);
4064 g_value_set_uint (value, self->prop.num_iframes);
4066 case PROP_NUM_REF_FRAMES:
4067 g_value_set_uint (value, self->prop.num_ref_frames);
4069 case PROP_B_PYRAMID:
4070 g_value_set_boolean (value, self->prop.b_pyramid);
4072 case PROP_NUM_SLICES:
4073 g_value_set_uint (value, self->prop.num_slices);
4076 g_value_set_uint (value, self->prop.min_qp);
4079 g_value_set_uint (value, self->prop.max_qp);
4082 g_value_set_uint (value, self->prop.qp_i);
4085 g_value_set_uint (value, self->prop.qp_p);
4088 g_value_set_uint (value, self->prop.qp_b);
4091 g_value_set_boolean (value, self->prop.use_dct8x8);
4094 g_value_set_boolean (value, self->prop.use_cabac);
4097 g_value_set_boolean (value, self->prop.use_trellis);
4100 g_value_set_boolean (value, self->prop.aud);
4103 g_value_set_enum (value, self->prop.mbbrc);
4106 g_value_set_uint (value, self->prop.bitrate);
4108 case PROP_TARGET_PERCENTAGE:
4109 g_value_set_uint (value, self->prop.target_percentage);
4111 case PROP_TARGET_USAGE:
4112 g_value_set_uint (value, self->prop.target_usage);
4114 case PROP_RATE_CONTROL:
4115 g_value_set_enum (value, self->prop.rc_ctrl);
4118 g_value_set_uint (value, self->prop.cpb_size);
4120 case PROP_DEVICE_PATH:{
4121 if (!(self->display && GST_IS_VA_DISPLAY_DRM (self->display))) {
4122 g_value_set_string (value, NULL);
4125 g_object_get_property (G_OBJECT (self->display), "path", value);
4129 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4132 GST_OBJECT_UNLOCK (self);
4137 gchar *render_device_path;
4144 gst_va_h264_enc_class_init (gpointer g_klass, gpointer class_data)
4146 GstCaps *src_doc_caps, *sink_doc_caps;
4147 GObjectClass *const object_class = G_OBJECT_CLASS (g_klass);
4148 GstElementClass *const element_class = GST_ELEMENT_CLASS (g_klass);
4149 GstVideoEncoderClass *const venc_class = GST_VIDEO_ENCODER_CLASS (g_klass);
4150 GstVaH264EncClass *const klass = GST_VA_H264_ENC_CLASS (g_klass);
4151 GstPadTemplate *sink_pad_templ, *src_pad_templ;
4152 struct CData *cdata = class_data;
4155 parent_class = g_type_class_peek_parent (g_klass);
4157 klass->render_device_path = g_strdup (cdata->render_device_path);
4158 klass->codec = H264;
4160 if (cdata->description) {
4161 long_name = g_strdup_printf ("VA-API H.264 Encoder in %s",
4162 cdata->description);
4164 long_name = g_strdup ("VA-API H.264 Encoder");
4167 gst_element_class_set_metadata (element_class, long_name,
4168 "Codec/Encoder/Video/Hardware", "VA-API based H.264 video encoder",
4169 "He Junyan <junyan.he@intel.com>");
4171 sink_doc_caps = gst_caps_from_string (sink_caps_str);
4172 src_doc_caps = gst_caps_from_string (src_caps_str);
4174 sink_pad_templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
4176 gst_element_class_add_pad_template (element_class, sink_pad_templ);
4178 gst_pad_template_set_documentation_caps (sink_pad_templ, sink_doc_caps);
4179 gst_caps_unref (sink_doc_caps);
4181 src_pad_templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
4183 gst_element_class_add_pad_template (element_class, src_pad_templ);
4185 gst_pad_template_set_documentation_caps (src_pad_templ, src_doc_caps);
4186 gst_caps_unref (src_doc_caps);
4188 object_class->set_property = gst_va_h264_enc_set_property;
4189 object_class->get_property = gst_va_h264_enc_get_property;
4191 element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_h264_enc_set_context);
4192 venc_class->open = GST_DEBUG_FUNCPTR (gst_va_h264_enc_open);
4193 venc_class->start = GST_DEBUG_FUNCPTR (gst_va_h264_enc_start);
4194 venc_class->close = GST_DEBUG_FUNCPTR (gst_va_h264_enc_close);
4195 venc_class->stop = GST_DEBUG_FUNCPTR (gst_va_h264_enc_stop);
4196 venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_handle_frame);
4197 venc_class->finish = GST_DEBUG_FUNCPTR (gst_va_h264_enc_finish);
4198 venc_class->flush = GST_DEBUG_FUNCPTR (gst_va_h264_enc_flush);
4199 venc_class->set_format = GST_DEBUG_FUNCPTR (gst_va_h264_enc_set_format);
4200 venc_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_h264_enc_get_caps);
4201 venc_class->propose_allocation =
4202 GST_DEBUG_FUNCPTR (gst_va_h264_enc_propose_allocation);
4203 venc_class->src_query = GST_DEBUG_FUNCPTR (gst_va_h264_enc_src_query);
4204 venc_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_h264_enc_sink_query);
4206 klass->reconfig = GST_DEBUG_FUNCPTR (gst_va_h264_enc_reconfig);
4207 klass->push_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_push_frame);
4208 klass->pop_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_pop_frame);
4209 klass->encode_frame = GST_DEBUG_FUNCPTR (gst_va_h264_enc_encode_frame);
4212 g_free (cdata->description);
4213 g_free (cdata->render_device_path);
4214 gst_caps_unref (cdata->src_caps);
4215 gst_caps_unref (cdata->sink_caps);
4219 * GstVaEncoder:key-int-max:
4221 * The maximal distance between two keyframes.
4223 properties[PROP_KEY_INT_MAX] = g_param_spec_uint ("key-int-max",
4224 "Key frame maximal interval",
4225 "The maximal distance between two keyframes. It decides the size of GOP"
4226 " (0: auto-calculate)", 0, MAX_GOP_SIZE, 0,
4227 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4230 * GstVaH264Enc:b-frames:
4232 * Number of B-frames between two reference frames.
4234 properties[PROP_BFRAMES] = g_param_spec_uint ("b-frames", "B Frames",
4235 "Number of B frames between I and P reference frames", 0, 31, 0,
4236 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4239 * GstVaH264Enc:i-frames:
4241 * Force the number of i-frames insertion within one GOP.
4243 properties[PROP_IFRAMES] = g_param_spec_uint ("i-frames", "I Frames",
4244 "Force the number of I frames insertion within one GOP, not including the "
4245 "first IDR frame", 0, 1023, 0,
4246 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4249 * GstVaH264Enc:ref-frames:
4251 * The number of reference frames.
4253 properties[PROP_NUM_REF_FRAMES] = g_param_spec_uint ("ref-frames",
4254 "Number of Reference Frames",
4255 "Number of reference frames, including both the forward and the backward",
4256 0, 16, 3, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4259 * GstVaH264Enc:b-pyramid:
4261 * Enable the b-pyramid reference structure in GOP.
4263 properties[PROP_B_PYRAMID] = g_param_spec_boolean ("b-pyramid", "b pyramid",
4264 "Enable the b-pyramid reference structure in the GOP", FALSE,
4265 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4267 * GstVaH264Enc:num-slices:
4269 * The number of slices per frame.
4271 properties[PROP_NUM_SLICES] = g_param_spec_uint ("num-slices",
4272 "Number of Slices", "Number of slices per frame", 1, 200, 1,
4273 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4276 * GstVaH264Enc:max-qp:
4278 * The maximum quantizer value.
4280 properties[PROP_MAX_QP] = g_param_spec_uint ("max-qp", "Maximum QP",
4281 "Maximum quantizer value for each frame", 0, 51, 51,
4282 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4285 * GstVaH264Enc:min-qp:
4287 * The minimum quantizer value.
4289 properties[PROP_MIN_QP] = g_param_spec_uint ("min-qp", "Minimum QP",
4290 "Minimum quantizer value for each frame", 0, 51, 1,
4291 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4296 * The quantizer value for I frame. In CQP mode, it specifies the QP of
4297 * I frame, in other mode, it specifies the init QP of all frames.
4299 properties[PROP_QP_I] = g_param_spec_uint ("qpi", "I Frame QP",
4300 "The quantizer value for I frame. In CQP mode, it specifies the QP of I "
4301 "frame, in other mode, it specifies the init QP of all frames", 0, 51, 26,
4302 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4307 * The quantizer value for P frame. This is available only in CQP mode.
4309 properties[PROP_QP_P] = g_param_spec_uint ("qpp",
4310 "The quantizer value for P frame",
4311 "The quantizer value for P frame. This is available only in CQP mode",
4313 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4318 * The quantizer value for B frame. This is available only in CQP mode.
4320 properties[PROP_QP_B] = g_param_spec_uint ("qpb",
4321 "The quantizer value for B frame",
4322 "The quantizer value for B frame. This is available only in CQP mode",
4324 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4327 * GstVaH264Enc:dct8x8:
4329 * Enable adaptive use of 8x8 transforms in I-frames. This improves
4330 * the compression ratio but requires high profile at least.
4332 properties[PROP_DCT8X8] = g_param_spec_boolean ("dct8x8",
4334 "Enable adaptive use of 8x8 transforms in I-frames", TRUE,
4335 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4338 * GstVaH264Enc:cabac:
4340 * It enables CABAC entropy coding mode to improve compression ratio,
4341 * but requires main profile at least.
4343 properties[PROP_CABAC] = g_param_spec_boolean ("cabac", "Enable CABAC",
4344 "Enable CABAC entropy coding mode", TRUE,
4345 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4348 * GstVaH264Enc:trellis:
4350 * It enable the trellis quantization method.
4351 * Trellis is an improved quantization algorithm.
4353 properties[PROP_TRELLIS] = g_param_spec_boolean ("trellis", "Enable trellis",
4354 "Enable the trellis quantization method", FALSE,
4355 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4360 * Insert the AU (Access Unit) delimeter for each frame.
4362 properties[PROP_AUD] = g_param_spec_boolean ("aud", "Insert AUD",
4363 "Insert AU (Access Unit) delimeter for each frame", FALSE,
4364 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4367 * GstVaH264Enc:mbbrc:
4369 * Macroblock level bitrate control.
4370 * This is not compatible with Constant QP rate control.
4372 properties[PROP_MBBRC] = g_param_spec_enum ("mbbrc",
4373 "Macroblock level Bitrate Control",
4374 "Macroblock level Bitrate Control. It is not compatible with CQP",
4375 gst_va_h264_enc_mbbrc_get_type (), 0,
4376 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4379 * GstVaH264Enc:bitrate:
4381 * The desired target bitrate, expressed in kbps.
4382 * This is not available in CQP mode.
4384 * CBR: This applies equally to the minimum, maximum and target bitrate.
4385 * VBR: This applies to the target bitrate. The driver will use the
4386 * "target-percentage" together to calculate the minimum and maximum bitrate.
4387 * VCM: This applies to the target bitrate. The minimum and maximum bitrate
4390 properties[PROP_BITRATE] = g_param_spec_uint ("bitrate", "Bitrate (kbps)",
4391 "The desired bitrate expressed in kbps (0: auto-calculate)",
4393 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4396 * GstVaH264Enc:target-percentage:
4398 * The target percentage of the max bitrate, and expressed in uint,
4399 * equal to "target percentage"*100.
4400 * "target percentage" = "target bitrate" * 100 / "max bitrate"
4401 * This is available only when rate-control is VBR.
4402 * The driver uses it to calculate the minimum and maximum bitrate.
4404 properties[PROP_TARGET_PERCENTAGE] = g_param_spec_uint ("target-percentage",
4405 "target bitrate percentage",
4406 "The percentage for 'target bitrate'/'maximum bitrate' (Only in VBR)",
4408 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4411 * GstVaH264Enc:target-usage:
4413 * The target usage of the encoder. It controls and balances the encoding
4414 * speed and the encoding quality. The lower value has better quality but
4415 * slower speed, the higher value has faster speed but lower quality.
4417 properties[PROP_TARGET_USAGE] = g_param_spec_uint ("target-usage",
4419 "The target usage to control and balance the encoding speed/quality",
4420 1, 7, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4423 * GstVaH264Enc:cpb-size:
4425 * The desired max CPB size in Kb (0: auto-calculate).
4427 properties[PROP_CPB_SIZE] = g_param_spec_uint ("cpb-size",
4428 "max CPB size in Kb",
4429 "The desired max CPB size in Kb (0: auto-calculate)", 0, 2000 * 1024, 0,
4430 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4433 * GstVaH264Enc:rate-control:
4435 * The desired rate control mode for the encoder.
4437 properties[PROP_RATE_CONTROL] = g_param_spec_enum ("rate-control",
4438 "rate control mode", "The desired rate control mode for the encoder",
4439 GST_TYPE_VA_ENCODER_RATE_CONTROL, VA_RC_CBR,
4440 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
4442 properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
4443 "Device Path", "DRM device path", NULL,
4444 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
4446 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
4448 gst_type_mark_as_plugin_api (gst_va_encoder_rate_control_get_type (), 0);
4449 gst_type_mark_as_plugin_api (gst_va_h264_enc_mbbrc_get_type (), 0);
4453 _complete_src_caps (GstCaps * srccaps)
4455 GstCaps *caps = gst_caps_copy (srccaps);
4456 GValue val = G_VALUE_INIT;
4458 g_value_init (&val, G_TYPE_STRING);
4459 g_value_set_string (&val, "au");
4460 gst_caps_set_value (caps, "alignment", &val);
4461 g_value_unset (&val);
4463 g_value_init (&val, G_TYPE_STRING);
4464 g_value_set_string (&val, "byte-stream");
4465 gst_caps_set_value (caps, "stream-format", &val);
4466 g_value_unset (&val);
4472 gst_va_h264_enc_register (GstPlugin * plugin, GstVaDevice * device,
4473 GstCaps * sink_caps, GstCaps * src_caps, guint rank)
4475 static GOnce debug_once = G_ONCE_INIT;
4477 GTypeInfo type_info = {
4478 .class_size = sizeof (GstVaH264EncClass),
4479 .class_init = gst_va_h264_enc_class_init,
4480 .instance_size = sizeof (GstVaH264Enc),
4481 .instance_init = gst_va_h264_enc_init,
4483 struct CData *cdata;
4485 gchar *type_name, *feature_name;
4487 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
4488 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
4489 g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
4490 g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
4492 cdata = g_new (struct CData, 1);
4493 cdata->description = NULL;
4494 cdata->render_device_path = g_strdup (device->render_device_path);
4495 cdata->sink_caps = gst_caps_ref (sink_caps);
4496 cdata->src_caps = _complete_src_caps (src_caps);
4498 /* class data will be leaked if the element never gets instantiated */
4499 GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
4500 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
4501 GST_MINI_OBJECT_FLAG_SET (cdata->src_caps,
4502 GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
4504 type_info.class_data = cdata;
4505 type_name = g_strdup ("GstVaH264Enc");
4506 feature_name = g_strdup ("vah264enc");
4508 /* The first encoder to be registered should use a constant name,
4509 * like vah264enc, for any additional encoders, we create unique
4510 * names, using inserting the render device name. */
4511 if (g_type_from_name (type_name)) {
4512 gchar *basename = g_path_get_basename (device->render_device_path);
4514 g_free (feature_name);
4515 type_name = g_strdup_printf ("GstVa%sH264Enc", basename);
4516 feature_name = g_strdup_printf ("va%sh264enc", basename);
4517 cdata->description = basename;
4518 /* lower rank for non-first device */
4523 g_once (&debug_once, _register_debug_category, NULL);
4524 type = g_type_register_static (GST_TYPE_VIDEO_ENCODER,
4525 type_name, &type_info, 0);
4526 ret = gst_element_register (plugin, feature_name, rank, type);
4529 g_free (feature_name);