mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
encoder: h264: add initial support for H.264 Stereo High profile.
Add initial support for Subset SPS, Prefix NAL and Slice Extension NAL for non-base-view streams encoding, and the usual SPS, PPS and Slice NALs for base-view encoding. The H.264 Stereo High profile encoding mode will be turned on when the "num-views" parameter is set to 2. The source (raw) YUV frames will be considered as Left/Right view, alternatively. Each of the two views has its own frames reordering pool and reference frames list management system. Inter-view references are not supported yet, so the views are encoded independently from each other. Signed-off-by: Li Xiaowei <xiaowei.a.li@intel.com> [limited to Stereo High profile per the definition of MAX_NUM_VIEWS] Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
This commit is contained in:
parent
5323570a35
commit
7bdf3fa177
4 changed files with 283 additions and 22 deletions
|
@ -83,7 +83,10 @@ typedef enum
|
||||||
GST_VAAPI_ENCODER_H264_NAL_IDR = 5, /* ref_idc != 0 */
|
GST_VAAPI_ENCODER_H264_NAL_IDR = 5, /* ref_idc != 0 */
|
||||||
GST_VAAPI_ENCODER_H264_NAL_SEI = 6, /* ref_idc == 0 */
|
GST_VAAPI_ENCODER_H264_NAL_SEI = 6, /* ref_idc == 0 */
|
||||||
GST_VAAPI_ENCODER_H264_NAL_SPS = 7,
|
GST_VAAPI_ENCODER_H264_NAL_SPS = 7,
|
||||||
GST_VAAPI_ENCODER_H264_NAL_PPS = 8
|
GST_VAAPI_ENCODER_H264_NAL_PPS = 8,
|
||||||
|
GST_VAAPI_ENCODER_H264_NAL_PREFIX = 14, /* mvc nal prefix */
|
||||||
|
GST_VAAPI_ENCODER_H264_NAL_SUBSET_SPS = 15,
|
||||||
|
GST_VAAPI_ENCODER_H264_NAL_SLICE_EXT = 20
|
||||||
} GstVaapiEncoderH264NalType;
|
} GstVaapiEncoderH264NalType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -875,6 +878,12 @@ ensure_profile (GstVaapiEncoderH264 * encoder)
|
||||||
if (encoder->use_dct8x8)
|
if (encoder->use_dct8x8)
|
||||||
profile = GST_VAAPI_PROFILE_H264_HIGH;
|
profile = GST_VAAPI_PROFILE_H264_HIGH;
|
||||||
|
|
||||||
|
/* MVC profiles coding tools */
|
||||||
|
if (encoder->num_views == 2)
|
||||||
|
profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
|
||||||
|
else if (encoder->num_views > 2)
|
||||||
|
profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
|
||||||
|
|
||||||
encoder->profile = profile;
|
encoder->profile = profile;
|
||||||
encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
|
encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1065,6 +1074,8 @@ add_packed_sequence_header (GstVaapiEncoderH264 * encoder,
|
||||||
GstBitWriter bs;
|
GstBitWriter bs;
|
||||||
VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 };
|
VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 };
|
||||||
const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
|
const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
|
||||||
|
GstVaapiProfile profile = encoder->profile;
|
||||||
|
|
||||||
VAEncMiscParameterHRD hrd_params;
|
VAEncMiscParameterHRD hrd_params;
|
||||||
guint32 data_bit_size;
|
guint32 data_bit_size;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
|
@ -1075,7 +1086,16 @@ add_packed_sequence_header (GstVaapiEncoderH264 * encoder,
|
||||||
WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
|
WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
|
||||||
bs_write_nal_header (&bs,
|
bs_write_nal_header (&bs,
|
||||||
GST_VAAPI_ENCODER_H264_NAL_REF_IDC_HIGH, GST_VAAPI_ENCODER_H264_NAL_SPS);
|
GST_VAAPI_ENCODER_H264_NAL_REF_IDC_HIGH, GST_VAAPI_ENCODER_H264_NAL_SPS);
|
||||||
bs_write_sps (&bs, seq_param, encoder->profile, &hrd_params);
|
|
||||||
|
/* Set High profile for encoding the MVC base view. Otherwise, some
|
||||||
|
traditional decoder cannot recognize MVC profile streams with
|
||||||
|
only the base view in there */
|
||||||
|
if (profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
|
||||||
|
profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH)
|
||||||
|
profile = GST_VAAPI_PROFILE_H264_HIGH;
|
||||||
|
|
||||||
|
bs_write_sps (&bs, seq_param, profile, &hrd_params);
|
||||||
|
|
||||||
g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
|
g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
|
||||||
data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
|
data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
|
||||||
data = GST_BIT_WRITER_DATA (&bs);
|
data = GST_BIT_WRITER_DATA (&bs);
|
||||||
|
@ -1106,6 +1126,56 @@ bs_error:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
add_packed_sequence_header_mvc (GstVaapiEncoderH264 * encoder,
|
||||||
|
GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
|
||||||
|
{
|
||||||
|
GstVaapiEncPackedHeader *packed_seq;
|
||||||
|
GstBitWriter bs;
|
||||||
|
VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
|
||||||
|
VAEncSequenceParameterBufferH264_MVC *mvc_seq_param = sequence->param;
|
||||||
|
VAEncMiscParameterHRD hrd_params;
|
||||||
|
guint32 data_bit_size;
|
||||||
|
guint8 *data;
|
||||||
|
|
||||||
|
fill_hrd_params (encoder, &hrd_params);
|
||||||
|
|
||||||
|
/* non-base layer, pack one subset sps */
|
||||||
|
gst_bit_writer_init (&bs, 128 * 8);
|
||||||
|
WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
|
||||||
|
bs_write_nal_header (&bs,
|
||||||
|
GST_VAAPI_ENCODER_H264_NAL_REF_IDC_HIGH,
|
||||||
|
GST_VAAPI_ENCODER_H264_NAL_SUBSET_SPS);
|
||||||
|
|
||||||
|
bs_write_subset_sps (&bs, mvc_seq_param, encoder->profile, &hrd_params);
|
||||||
|
|
||||||
|
g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
|
||||||
|
data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
|
||||||
|
data = GST_BIT_WRITER_DATA (&bs);
|
||||||
|
|
||||||
|
packed_header_param_buffer.type = VAEncPackedHeaderSequence;
|
||||||
|
packed_header_param_buffer.bit_length = data_bit_size;
|
||||||
|
packed_header_param_buffer.has_emulation_bytes = 0;
|
||||||
|
|
||||||
|
packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
|
||||||
|
&packed_header_param_buffer, sizeof (packed_header_param_buffer),
|
||||||
|
data, (data_bit_size + 7) / 8);
|
||||||
|
g_assert (packed_seq);
|
||||||
|
|
||||||
|
gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
|
||||||
|
gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) & packed_seq, NULL);
|
||||||
|
gst_bit_writer_clear (&bs, TRUE);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
bs_error:
|
||||||
|
{
|
||||||
|
GST_WARNING ("failed to write SPS NAL unit");
|
||||||
|
gst_bit_writer_clear (&bs, TRUE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Adds the supplied picture header (PPS) to the list of packed
|
/* Adds the supplied picture header (PPS) to the list of packed
|
||||||
headers to pass down as-is to the encoder */
|
headers to pass down as-is to the encoder */
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -1266,7 +1336,7 @@ fill_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncSequence * sequence)
|
||||||
&encoder->ref_pools[encoder->view_idx];
|
&encoder->ref_pools[encoder->view_idx];
|
||||||
|
|
||||||
memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264));
|
memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264));
|
||||||
seq_param->seq_parameter_set_id = 0;
|
seq_param->seq_parameter_set_id = encoder->view_idx;
|
||||||
seq_param->level_idc = encoder->level_idc;
|
seq_param->level_idc = encoder->level_idc;
|
||||||
seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
|
seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
|
||||||
seq_param->ip_period = 1 + encoder->num_bframes;
|
seq_param->ip_period = 1 + encoder->num_bframes;
|
||||||
|
@ -1342,6 +1412,125 @@ fill_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncSequence * sequence)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free MVC sequence parameters used for encoding */
|
||||||
|
static void
|
||||||
|
free_sequence_mvc (GstVaapiEncSequence * sequence)
|
||||||
|
{
|
||||||
|
guint i, j;
|
||||||
|
VAEncSequenceParameterBufferH264_MVC *mvc_seq = sequence->param;
|
||||||
|
|
||||||
|
if (mvc_seq->view_list) {
|
||||||
|
g_free (mvc_seq->view_list);
|
||||||
|
mvc_seq->view_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mvc_seq->level_value_list) {
|
||||||
|
for (i = 0; i <= mvc_seq->num_level_values_signalled_minus1; i++) {
|
||||||
|
struct H264SPSExtMVCLevelValue *level_value =
|
||||||
|
&(mvc_seq->level_value_list[i]);
|
||||||
|
for (j = 0; j < level_value->num_applicable_ops_minus1 + 1; j++) {
|
||||||
|
struct H264SPSExtMVCLevelValueOps *level_value_ops =
|
||||||
|
&(level_value->level_value_ops_list[j]);
|
||||||
|
if (level_value_ops->target_view_id_list) {
|
||||||
|
g_free (level_value_ops->target_view_id_list);
|
||||||
|
level_value_ops->target_view_id_list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (level_value->level_value_ops_list);
|
||||||
|
level_value->level_value_ops_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (mvc_seq->level_value_list);
|
||||||
|
mvc_seq->level_value_list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fills in VA sequence parameter buffer for MVC encoding */
|
||||||
|
static gboolean
|
||||||
|
fill_sequence_mvc (GstVaapiEncoderH264 * encoder,
|
||||||
|
GstVaapiEncSequence * sequence)
|
||||||
|
{
|
||||||
|
guint i, j, k;
|
||||||
|
VAEncSequenceParameterBufferH264_MVC *mvc_seq = sequence->param;
|
||||||
|
guint16 num_views_minus1, num_level_values_signalled_minus1;
|
||||||
|
struct H264SPSExtMVCViewInfo *view = NULL;
|
||||||
|
struct H264SPSExtMVCLevelValue *level_value = NULL;
|
||||||
|
struct H264SPSExtMVCLevelValueOps *level_value_ops = NULL;
|
||||||
|
|
||||||
|
memset (mvc_seq, 0, sizeof (VAEncSequenceParameterBufferH264_MVC));
|
||||||
|
|
||||||
|
if (!fill_sequence (encoder, sequence))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
num_views_minus1 = encoder->num_views - 1;
|
||||||
|
g_assert (num_views_minus1 < 1024);
|
||||||
|
mvc_seq->num_views_minus1 = num_views_minus1;
|
||||||
|
|
||||||
|
if (!mvc_seq->view_list)
|
||||||
|
mvc_seq->view_list =
|
||||||
|
g_new0 (struct H264SPSExtMVCViewInfo, num_views_minus1 + 1);
|
||||||
|
|
||||||
|
for (i = 0; i <= num_views_minus1; i++) {
|
||||||
|
view = &(mvc_seq->view_list[i]);
|
||||||
|
view->view_id = i;
|
||||||
|
|
||||||
|
view->num_anchor_refs_l0 = 15;
|
||||||
|
for (j = 0; j < view->num_anchor_refs_l0; j++)
|
||||||
|
view->anchor_ref_l0[j] = 0;
|
||||||
|
|
||||||
|
view->num_anchor_refs_l1 = 15;
|
||||||
|
for (j = 0; j < view->num_anchor_refs_l1; j++)
|
||||||
|
view->anchor_ref_l1[j] = 0;
|
||||||
|
|
||||||
|
view->num_non_anchor_refs_l0 = 15;
|
||||||
|
for (j = 0; j < view->num_non_anchor_refs_l0; j++)
|
||||||
|
view->non_anchor_ref_l0[j] = 0;
|
||||||
|
|
||||||
|
view->num_non_anchor_refs_l1 = 15;
|
||||||
|
for (j = 0; j < view->num_non_anchor_refs_l1; j++)
|
||||||
|
view->non_anchor_ref_l1[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_level_values_signalled_minus1 = 0;
|
||||||
|
g_assert (num_level_values_signalled_minus1 < 64);
|
||||||
|
mvc_seq->num_level_values_signalled_minus1 =
|
||||||
|
num_level_values_signalled_minus1;
|
||||||
|
|
||||||
|
if (!mvc_seq->level_value_list)
|
||||||
|
mvc_seq->level_value_list = g_new0 (struct H264SPSExtMVCLevelValue,
|
||||||
|
num_level_values_signalled_minus1 + 1);
|
||||||
|
|
||||||
|
for (i = 0; i <= num_level_values_signalled_minus1; i++) {
|
||||||
|
level_value = &(mvc_seq->level_value_list[i]);
|
||||||
|
|
||||||
|
guint16 num_applicable_ops_minus1 = 0;
|
||||||
|
g_assert (num_applicable_ops_minus1 < 1024);
|
||||||
|
level_value->num_applicable_ops_minus1 = num_applicable_ops_minus1;
|
||||||
|
level_value->level_idc = encoder->level;
|
||||||
|
|
||||||
|
if (!level_value->level_value_ops_list)
|
||||||
|
level_value->level_value_ops_list =
|
||||||
|
g_new0 (struct H264SPSExtMVCLevelValueOps,
|
||||||
|
num_applicable_ops_minus1 + 1);
|
||||||
|
for (j = 0; j <= num_applicable_ops_minus1; j++) {
|
||||||
|
level_value_ops = &(level_value->level_value_ops_list[j]);
|
||||||
|
|
||||||
|
guint16 num_target_views_minus1 = 1;
|
||||||
|
level_value_ops->num_target_views_minus1 = num_target_views_minus1;
|
||||||
|
level_value_ops->num_views_minus1 = num_views_minus1;
|
||||||
|
|
||||||
|
if (!level_value_ops->target_view_id_list)
|
||||||
|
level_value_ops->target_view_id_list =
|
||||||
|
g_new0 (guint16, num_views_minus1 + 1);
|
||||||
|
|
||||||
|
for (k = 0; k <= num_target_views_minus1; k++)
|
||||||
|
level_value_ops->target_view_id_list[k] = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fills in VA picture parameter buffer */
|
/* Fills in VA picture parameter buffer */
|
||||||
static gboolean
|
static gboolean
|
||||||
fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
|
@ -1378,8 +1567,8 @@ fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
}
|
}
|
||||||
pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
|
pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
|
||||||
|
|
||||||
pic_param->pic_parameter_set_id = 0;
|
pic_param->pic_parameter_set_id = encoder->view_idx;
|
||||||
pic_param->seq_parameter_set_id = 0;
|
pic_param->seq_parameter_set_id = encoder->view_idx;
|
||||||
pic_param->last_picture = 0; /* means last encoding picture */
|
pic_param->last_picture = 0; /* means last encoding picture */
|
||||||
pic_param->frame_num = picture->frame_num;
|
pic_param->frame_num = picture->frame_num;
|
||||||
pic_param->pic_init_qp = encoder->init_qp;
|
pic_param->pic_init_qp = encoder->init_qp;
|
||||||
|
@ -1411,6 +1600,25 @@ fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fill_mvc_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
|
GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
|
||||||
|
{
|
||||||
|
VAEncPictureParameterBufferH264_MVC *const mvc_pic = picture->param;
|
||||||
|
|
||||||
|
if (!fill_picture (encoder, picture, codedbuf, surface))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
mvc_pic->view_id = encoder->view_idx;
|
||||||
|
mvc_pic->inter_view_flag = 0;
|
||||||
|
if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
|
||||||
|
mvc_pic->anchor_pic_flag = 1;
|
||||||
|
else
|
||||||
|
mvc_pic->anchor_pic_flag = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Adds slice headers to picture */
|
/* Adds slice headers to picture */
|
||||||
static gboolean
|
static gboolean
|
||||||
add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
|
@ -1448,7 +1656,7 @@ add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
slice_param->macroblock_info = VA_INVALID_ID;
|
slice_param->macroblock_info = VA_INVALID_ID;
|
||||||
slice_param->slice_type = h264_get_slice_type (picture->type);
|
slice_param->slice_type = h264_get_slice_type (picture->type);
|
||||||
g_assert (slice_param->slice_type != -1);
|
g_assert (slice_param->slice_type != -1);
|
||||||
slice_param->pic_parameter_set_id = 0;
|
slice_param->pic_parameter_set_id = encoder->view_idx;
|
||||||
slice_param->idr_pic_id = encoder->idr_num;
|
slice_param->idr_pic_id = encoder->idr_num;
|
||||||
slice_param->pic_order_cnt_lsb = picture->poc;
|
slice_param->pic_order_cnt_lsb = picture->poc;
|
||||||
|
|
||||||
|
@ -1542,22 +1750,38 @@ add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
static gboolean
|
static gboolean
|
||||||
ensure_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
|
ensure_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
|
||||||
{
|
{
|
||||||
GstVaapiEncSequence *sequence;
|
GstVaapiEncSequence *sequence = NULL;
|
||||||
|
|
||||||
// Submit an SPS header before every new I-frame
|
// Submit an SPS header before every new I-frame
|
||||||
if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
|
if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder);
|
/* add subset sps for non-base view and sps for base view */
|
||||||
if (!sequence || !fill_sequence (encoder, sequence))
|
if (encoder->is_mvc && encoder->view_idx) {
|
||||||
goto error_create_seq_param;
|
sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264_MVC, encoder);
|
||||||
|
if (!sequence || !fill_sequence_mvc (encoder, sequence))
|
||||||
|
goto error_create_seq_param;
|
||||||
|
|
||||||
if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & VAEncPackedHeaderH264_SPS)
|
if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & VAEncPackedHeaderH264_SPS)
|
||||||
&& !add_packed_sequence_header (encoder, picture, sequence))
|
&& !add_packed_sequence_header_mvc (encoder, picture, sequence))
|
||||||
goto error_create_packed_seq_hdr;
|
goto error_create_packed_seq_hdr;
|
||||||
|
|
||||||
gst_vaapi_enc_picture_set_sequence (picture, sequence);
|
free_sequence_mvc (sequence);
|
||||||
gst_vaapi_codec_object_replace (&sequence, NULL);
|
|
||||||
|
} else {
|
||||||
|
sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder);
|
||||||
|
if (!sequence || !fill_sequence (encoder, sequence))
|
||||||
|
goto error_create_seq_param;
|
||||||
|
|
||||||
|
if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) & VAEncPackedHeaderH264_SPS)
|
||||||
|
&& !add_packed_sequence_header (encoder, picture, sequence))
|
||||||
|
goto error_create_packed_seq_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sequence) {
|
||||||
|
gst_vaapi_enc_picture_set_sequence (picture, sequence);
|
||||||
|
gst_vaapi_codec_object_replace (&sequence, NULL);
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -1619,8 +1843,14 @@ ensure_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
|
||||||
{
|
{
|
||||||
GstVaapiCodedBuffer *const codedbuf =
|
GstVaapiCodedBuffer *const codedbuf =
|
||||||
GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
|
GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
|
||||||
|
gboolean res = FALSE;
|
||||||
|
|
||||||
if (!fill_picture (encoder, picture, codedbuf, surface))
|
if (encoder->is_mvc)
|
||||||
|
res = fill_mvc_picture (encoder, picture, codedbuf, surface);
|
||||||
|
else
|
||||||
|
res = fill_picture (encoder, picture, codedbuf, surface);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
|
if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
|
||||||
|
@ -1787,6 +2017,7 @@ reset_properties (GstVaapiEncoderH264 * encoder)
|
||||||
encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
|
encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
|
||||||
encoder->idr_num = 0;
|
encoder->idr_num = 0;
|
||||||
|
|
||||||
|
encoder->is_mvc = encoder->num_views > 1;
|
||||||
for (i = 0; i < encoder->num_views; i++) {
|
for (i = 0; i < encoder->num_views; i++) {
|
||||||
GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
|
GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
|
||||||
ref_pool->max_reflist0_count = 1;
|
ref_pool->max_reflist0_count = 1;
|
||||||
|
@ -1958,13 +2189,21 @@ gst_vaapi_encoder_h264_reordering (GstVaapiEncoder * base_encoder,
|
||||||
{
|
{
|
||||||
GstVaapiEncoderH264 *const encoder =
|
GstVaapiEncoderH264 *const encoder =
|
||||||
GST_VAAPI_ENCODER_H264_CAST (base_encoder);
|
GST_VAAPI_ENCODER_H264_CAST (base_encoder);
|
||||||
GstVaapiH264ViewReorderPool *reorder_pool =
|
GstVaapiH264ViewReorderPool *reorder_pool = NULL;
|
||||||
&encoder->reorder_pools[encoder->view_idx];
|
|
||||||
GstVaapiEncPicture *picture;
|
GstVaapiEncPicture *picture;
|
||||||
gboolean is_idr = FALSE;
|
gboolean is_idr = FALSE;
|
||||||
|
|
||||||
*output = NULL;
|
*output = NULL;
|
||||||
|
|
||||||
|
/* encoding views alternatively for MVC */
|
||||||
|
if (encoder->is_mvc) {
|
||||||
|
if (frame)
|
||||||
|
encoder->view_idx = frame->system_frame_number % MAX_NUM_VIEWS;
|
||||||
|
else
|
||||||
|
encoder->view_idx = (encoder->view_idx + 1) % MAX_NUM_VIEWS;
|
||||||
|
}
|
||||||
|
reorder_pool = &encoder->reorder_pools[encoder->view_idx];
|
||||||
|
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
|
if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
|
||||||
return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
|
return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
|
||||||
|
@ -1983,7 +2222,11 @@ gst_vaapi_encoder_h264_reordering (GstVaapiEncoder * base_encoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new frame coming */
|
/* new frame coming */
|
||||||
picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame);
|
if (encoder->is_mvc)
|
||||||
|
picture = GST_VAAPI_ENC_PICTURE_NEW (H264_MVC, encoder, frame);
|
||||||
|
else
|
||||||
|
picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame);
|
||||||
|
|
||||||
if (!picture) {
|
if (!picture) {
|
||||||
GST_WARNING ("create H264 picture failed, frame timestamp:%"
|
GST_WARNING ("create H264 picture failed, frame timestamp:%"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
|
GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
|
||||||
|
@ -2077,7 +2320,8 @@ set_context_info (GstVaapiEncoder * base_encoder)
|
||||||
return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
|
return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
|
||||||
|
|
||||||
base_encoder->num_ref_frames =
|
base_encoder->num_ref_frames =
|
||||||
(encoder->num_bframes ? 2 : 1) + DEFAULT_SURFACES_COUNT;
|
((encoder->num_bframes ? 2 : 1) + DEFAULT_SURFACES_COUNT)
|
||||||
|
* encoder->view_idx;
|
||||||
|
|
||||||
/* Only YUV 4:2:0 formats are supported for now. This means that we
|
/* Only YUV 4:2:0 formats are supported for now. This means that we
|
||||||
have a limit of 3200 bits per macroblock. */
|
have a limit of 3200 bits per macroblock. */
|
||||||
|
@ -2219,6 +2463,9 @@ gst_vaapi_encoder_h264_set_property (GstVaapiEncoder * base_encoder,
|
||||||
case GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH:
|
case GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH:
|
||||||
encoder->cpb_length = g_value_get_uint (value);
|
encoder->cpb_length = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
|
case GST_VAAPI_ENCODER_H264_PROP_NUM_VIEWS:
|
||||||
|
encoder->num_views = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
|
return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
@ -2359,6 +2606,18 @@ gst_vaapi_encoder_h264_get_default_properties (void)
|
||||||
1, 10000, DEFAULT_CPB_LENGTH,
|
1, 10000, DEFAULT_CPB_LENGTH,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstVaapiEncoderH264:num-views:
|
||||||
|
*
|
||||||
|
* The number of views for MVC encoding .
|
||||||
|
*/
|
||||||
|
GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
|
||||||
|
GST_VAAPI_ENCODER_H264_PROP_NUM_VIEWS,
|
||||||
|
g_param_spec_uint ("num-views",
|
||||||
|
"Number of Views",
|
||||||
|
"Number of Views for MVC encoding",
|
||||||
|
1, MAX_NUM_VIEWS, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264;
|
||||||
* transforms in I-frames (bool).
|
* transforms in I-frames (bool).
|
||||||
* @GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH: Length of the CPB buffer
|
* @GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH: Length of the CPB buffer
|
||||||
* in milliseconds (uint).
|
* in milliseconds (uint).
|
||||||
|
* @GST_VAAPI_ENCODER_H264_PROP_NUM_VIEWS: Number of views per frame.
|
||||||
*
|
*
|
||||||
* The set of H.264 encoder specific configurable properties.
|
* The set of H.264 encoder specific configurable properties.
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +58,7 @@ typedef enum {
|
||||||
GST_VAAPI_ENCODER_H264_PROP_CABAC = -5,
|
GST_VAAPI_ENCODER_H264_PROP_CABAC = -5,
|
||||||
GST_VAAPI_ENCODER_H264_PROP_DCT8X8 = -6,
|
GST_VAAPI_ENCODER_H264_PROP_DCT8X8 = -6,
|
||||||
GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH = -7,
|
GST_VAAPI_ENCODER_H264_PROP_CPB_LENGTH = -7,
|
||||||
|
GST_VAAPI_ENCODER_H264_PROP_NUM_VIEWS = -8,
|
||||||
} GstVaapiEncoderH264Prop;
|
} GstVaapiEncoderH264Prop;
|
||||||
|
|
||||||
GstVaapiEncoder *
|
GstVaapiEncoder *
|
||||||
|
|
|
@ -43,8 +43,8 @@ static const struct map gst_vaapi_h264_profile_map[] = {
|
||||||
{ GST_VAAPI_PROFILE_H264_HIGH_444, "high-4:4:4" },
|
{ GST_VAAPI_PROFILE_H264_HIGH_444, "high-4:4:4" },
|
||||||
{ GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE, "scalable-baseline" },
|
{ GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE, "scalable-baseline" },
|
||||||
{ GST_VAAPI_PROFILE_H264_SCALABLE_HIGH, "scalable-high" },
|
{ GST_VAAPI_PROFILE_H264_SCALABLE_HIGH, "scalable-high" },
|
||||||
{ GST_VAAPI_PROFILE_H264_STEREO_HIGH, "stereo-high" },
|
|
||||||
{ GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, "multiview-high" },
|
{ GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, "multiview-high" },
|
||||||
|
{ GST_VAAPI_PROFILE_H264_STEREO_HIGH, "stereo-high" },
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,7 +63,7 @@ static const char gst_vaapiencode_h264_sink_caps_str[] =
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
static const char gst_vaapiencode_h264_src_caps_str[] =
|
static const char gst_vaapiencode_h264_src_caps_str[] =
|
||||||
GST_CODEC_CAPS ", "
|
GST_CODEC_CAPS ", "
|
||||||
"profile = (string) { constrained-baseline, baseline, main, high }";
|
"profile = (string) { constrained-baseline, baseline, main, high, multiview-high, stereo-high }";
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
|
|
Loading…
Reference in a new issue