encoder: add bitrate API.

Add gst_vaapi_encoder_set_bitrate() interface to allow the user control
the bitrate for encoding. Currently, changing this parameter is only
valid before the first frame is encoded. Should the value be modified
afterwards, then GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
returned.

https://bugzilla.gnome.org/show_bug.cgi?id=719529
This commit is contained in:
Gwenole Beauchesne 2014-01-06 18:01:33 +01:00
parent a24c52e4d0
commit 70b3600f11
10 changed files with 70 additions and 29 deletions

View file

@ -491,6 +491,39 @@ error_unsupported_rate_control:
} }
} }
/**
* gst_vaapi_encoder_set_bitrate:
* @encoder: a #GstVaapiEncoder
* @bitrate: the requested bitrate (in kbps)
*
* Notifies the @encoder to use the supplied @bitrate value.
*
* Note: currently, the bitrate can only be specified before the first
* frame is encoded. Afterwards, any change to this parameter is
* invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
* returned.
*
* Return value: a #GstVaapiEncoderStatus
*/
GstVaapiEncoderStatus
gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate)
{
g_return_val_if_fail (encoder != NULL, 0);
if (encoder->bitrate != bitrate && encoder->num_codedbuf_queued > 0)
goto error_operation_failed;
encoder->bitrate = bitrate;
return GST_VAAPI_ENCODER_STATUS_SUCCESS;
/* ERRORS */
error_operation_failed:
{
GST_ERROR ("could not change bitrate value after encoding started");
return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
}
}
/* Base encoder initialization (internal) */ /* Base encoder initialization (internal) */
static gboolean static gboolean
gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display) gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)

View file

@ -90,6 +90,9 @@ GstVaapiEncoderStatus
gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder, gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder,
GstVaapiRateControl rate_control); GstVaapiRateControl rate_control);
GstVaapiEncoderStatus
gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate);
GstVaapiEncoderStatus GstVaapiEncoderStatus
gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder, gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
GstVideoCodecFrame * frame); GstVideoCodecFrame * frame);

View file

@ -852,6 +852,7 @@ static gboolean
fill_va_sequence_param (GstVaapiEncoderH264 * encoder, fill_va_sequence_param (GstVaapiEncoderH264 * encoder,
GstVaapiEncSequence * sequence) GstVaapiEncSequence * sequence)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
VAEncSequenceParameterBufferH264 *seq = sequence->param; VAEncSequenceParameterBufferH264 *seq = sequence->param;
guint width_in_mbs, height_in_mbs; guint width_in_mbs, height_in_mbs;
@ -863,8 +864,8 @@ fill_va_sequence_param (GstVaapiEncoderH264 * encoder,
seq->level_idc = encoder->level; seq->level_idc = encoder->level;
seq->intra_period = encoder->intra_period; seq->intra_period = encoder->intra_period;
seq->ip_period = 0; // ? seq->ip_period = 0; // ?
if (encoder->bitrate > 0) if (base_encoder->bitrate > 0)
seq->bits_per_second = encoder->bitrate * 1024; seq->bits_per_second = base_encoder->bitrate * 1024;
else else
seq->bits_per_second = 0; seq->bits_per_second = 0;
@ -912,12 +913,12 @@ fill_va_sequence_param (GstVaapiEncoderH264 * encoder,
} }
/*vui not set */ /*vui not set */
seq->vui_parameters_present_flag = (encoder->bitrate > 0 ? TRUE : FALSE); seq->vui_parameters_present_flag = (base_encoder->bitrate > 0 ? TRUE : FALSE);
if (seq->vui_parameters_present_flag) { if (seq->vui_parameters_present_flag) {
seq->vui_fields.bits.aspect_ratio_info_present_flag = FALSE; seq->vui_fields.bits.aspect_ratio_info_present_flag = FALSE;
seq->vui_fields.bits.bitstream_restriction_flag = FALSE; seq->vui_fields.bits.bitstream_restriction_flag = FALSE;
seq->vui_fields.bits.timing_info_present_flag = seq->vui_fields.bits.timing_info_present_flag =
(encoder->bitrate > 0 ? TRUE : FALSE); (base_encoder->bitrate > 0 ? TRUE : FALSE);
if (seq->vui_fields.bits.timing_info_present_flag) { if (seq->vui_fields.bits.timing_info_present_flag) {
seq->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder); seq->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder);
seq->time_scale = GST_VAAPI_ENCODER_FPS_N (encoder) * 2; seq->time_scale = GST_VAAPI_ENCODER_FPS_N (encoder) * 2;
@ -1209,6 +1210,7 @@ ensure_slices (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
static gboolean static gboolean
ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture) ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
GstVaapiEncMiscParam *misc = NULL; GstVaapiEncMiscParam *misc = NULL;
VAEncMiscParameterHRD *hrd; VAEncMiscParameterHRD *hrd;
VAEncMiscParameterRateControl *rate_control; VAEncMiscParameterRateControl *rate_control;
@ -1220,9 +1222,9 @@ ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
return FALSE; return FALSE;
gst_vaapi_enc_picture_add_misc_buffer (picture, misc); gst_vaapi_enc_picture_add_misc_buffer (picture, misc);
hrd = misc->impl; hrd = misc->impl;
if (encoder->bitrate > 0) { if (base_encoder->bitrate > 0) {
hrd->initial_buffer_fullness = encoder->bitrate * 1024 * 4; hrd->initial_buffer_fullness = base_encoder->bitrate * 1024 * 4;
hrd->buffer_size = encoder->bitrate * 1024 * 8; hrd->buffer_size = base_encoder->bitrate * 1024 * 8;
} else { } else {
hrd->initial_buffer_fullness = 0; hrd->initial_buffer_fullness = 0;
hrd->buffer_size = 0; hrd->buffer_size = 0;
@ -1239,8 +1241,8 @@ ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
gst_vaapi_enc_picture_add_misc_buffer (picture, misc); gst_vaapi_enc_picture_add_misc_buffer (picture, misc);
rate_control = misc->impl; rate_control = misc->impl;
memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl)); memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
if (encoder->bitrate) if (base_encoder->bitrate)
rate_control->bits_per_second = encoder->bitrate * 1024; rate_control->bits_per_second = base_encoder->bitrate * 1024;
else else
rate_control->bits_per_second = 0; rate_control->bits_per_second = 0;
rate_control->target_percentage = 70; rate_control->target_percentage = 70;
@ -1257,6 +1259,7 @@ ensure_misc (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
gboolean gboolean
init_encoder_public_attributes (GstVaapiEncoderH264 * encoder) init_encoder_public_attributes (GstVaapiEncoderH264 * encoder)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
guint width_mbs, height_mbs, total_mbs; guint width_mbs, height_mbs, total_mbs;
if (!GST_VAAPI_ENCODER_WIDTH (encoder) || if (!GST_VAAPI_ENCODER_WIDTH (encoder) ||
@ -1298,13 +1301,13 @@ init_encoder_public_attributes (GstVaapiEncoderH264 * encoder)
GST_VAAPI_RATECONTROL_VBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder) || GST_VAAPI_RATECONTROL_VBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder) ||
GST_VAAPI_RATECONTROL_VBR_CONSTRAINED == GST_VAAPI_RATECONTROL_VBR_CONSTRAINED ==
GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
if (!encoder->bitrate) if (!base_encoder->bitrate)
encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) *
GST_VAAPI_ENCODER_HEIGHT (encoder) * GST_VAAPI_ENCODER_HEIGHT (encoder) *
GST_VAAPI_ENCODER_FPS_N (encoder) / GST_VAAPI_ENCODER_FPS_N (encoder) /
GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024;
} else } else
encoder->bitrate = 0; base_encoder->bitrate = 0;
if (!encoder->slice_num) if (!encoder->slice_num)
encoder->slice_num = GST_VAAPI_ENCODER_H264_DEFAULT_SLICE_NUM; encoder->slice_num = GST_VAAPI_ENCODER_H264_DEFAULT_SLICE_NUM;
@ -1706,7 +1709,6 @@ gst_vaapi_encoder_h264_init (GstVaapiEncoder * base)
/* init attributes */ /* init attributes */
encoder->profile = 0; encoder->profile = 0;
encoder->level = 0; encoder->level = 0;
encoder->bitrate = 0;
encoder->idr_period = 0; encoder->idr_period = 0;
encoder->intra_period = 0; encoder->intra_period = 0;
encoder->init_qp = -1; encoder->init_qp = -1;

View file

@ -70,7 +70,6 @@ struct _GstVaapiEncoderH264
/* public */ /* public */
guint32 profile; guint32 profile;
guint32 level; guint32 level;
guint32 bitrate; /*kbps */
guint32 intra_period; guint32 intra_period;
guint32 idr_period; guint32 idr_period;
guint32 init_qp; /*default 24 */ guint32 init_qp; /*default 24 */

View file

@ -105,6 +105,8 @@ ensure_sampling_desity (GstVaapiEncoderMpeg2 * encoder)
static gboolean static gboolean
ensure_public_attributes (GstVaapiEncoderMpeg2 * encoder) ensure_public_attributes (GstVaapiEncoderMpeg2 * encoder)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
if (!GST_VAAPI_ENCODER_WIDTH (encoder) || if (!GST_VAAPI_ENCODER_WIDTH (encoder) ||
!GST_VAAPI_ENCODER_HEIGHT (encoder) || !GST_VAAPI_ENCODER_HEIGHT (encoder) ||
!GST_VAAPI_ENCODER_FPS_N (encoder) || !GST_VAAPI_ENCODER_FPS_N (encoder) ||
@ -128,13 +130,13 @@ ensure_public_attributes (GstVaapiEncoderMpeg2 * encoder)
/* default compress ratio 1: (4*8*1.5) */ /* default compress ratio 1: (4*8*1.5) */
if (GST_VAAPI_RATECONTROL_CBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) { if (GST_VAAPI_RATECONTROL_CBR == GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
if (!encoder->bitrate) if (!base_encoder->bitrate)
encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) * base_encoder->bitrate = GST_VAAPI_ENCODER_WIDTH (encoder) *
GST_VAAPI_ENCODER_HEIGHT (encoder) * GST_VAAPI_ENCODER_HEIGHT (encoder) *
GST_VAAPI_ENCODER_FPS_N (encoder) / GST_VAAPI_ENCODER_FPS_N (encoder) /
GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024; GST_VAAPI_ENCODER_FPS_D (encoder) / 4 / 1024;
} else } else
encoder->bitrate = 0; base_encoder->bitrate = 0;
return TRUE; return TRUE;
} }
@ -176,6 +178,7 @@ make_profile_and_level_indication (guint32 profile, guint32 level)
static gboolean static gboolean
fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence) fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
VAEncSequenceParameterBufferMPEG2 *seq = sequence->param; VAEncSequenceParameterBufferMPEG2 *seq = sequence->param;
memset (seq, 0, sizeof (VAEncSequenceParameterBufferMPEG2)); memset (seq, 0, sizeof (VAEncSequenceParameterBufferMPEG2));
@ -185,8 +188,8 @@ fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence)
seq->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder); seq->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder);
seq->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder); seq->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
if (encoder->bitrate > 0) if (base_encoder->bitrate > 0)
seq->bits_per_second = encoder->bitrate * 1024; seq->bits_per_second = base_encoder->bitrate * 1024;
else else
seq->bits_per_second = 0; seq->bits_per_second = 0;
@ -418,6 +421,7 @@ static gboolean
set_misc_parameters (GstVaapiEncoderMpeg2 * encoder, set_misc_parameters (GstVaapiEncoderMpeg2 * encoder,
GstVaapiEncPicture * picture) GstVaapiEncPicture * picture)
{ {
GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
GstVaapiEncMiscParam *misc = NULL; GstVaapiEncMiscParam *misc = NULL;
VAEncMiscParameterHRD *hrd; VAEncMiscParameterHRD *hrd;
VAEncMiscParameterRateControl *rate_control; VAEncMiscParameterRateControl *rate_control;
@ -429,9 +433,9 @@ set_misc_parameters (GstVaapiEncoderMpeg2 * encoder,
return FALSE; return FALSE;
gst_vaapi_enc_picture_add_misc_buffer (picture, misc); gst_vaapi_enc_picture_add_misc_buffer (picture, misc);
hrd = misc->impl; hrd = misc->impl;
if (encoder->bitrate > 0) { if (base_encoder->bitrate > 0) {
hrd->initial_buffer_fullness = encoder->bitrate * 1024 * 4; hrd->initial_buffer_fullness = base_encoder->bitrate * 1024 * 4;
hrd->buffer_size = encoder->bitrate * 1024 * 8; hrd->buffer_size = base_encoder->bitrate * 1024 * 8;
} else { } else {
hrd->initial_buffer_fullness = 0; hrd->initial_buffer_fullness = 0;
hrd->buffer_size = 0; hrd->buffer_size = 0;
@ -447,8 +451,8 @@ set_misc_parameters (GstVaapiEncoderMpeg2 * encoder,
gst_vaapi_enc_picture_add_misc_buffer (picture, misc); gst_vaapi_enc_picture_add_misc_buffer (picture, misc);
rate_control = misc->impl; rate_control = misc->impl;
memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl)); memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
if (encoder->bitrate) if (base_encoder->bitrate)
rate_control->bits_per_second = encoder->bitrate * 1024; rate_control->bits_per_second = base_encoder->bitrate * 1024;
else else
rate_control->bits_per_second = 0; rate_control->bits_per_second = 0;
rate_control->target_percentage = 70; rate_control->target_percentage = 70;

View file

@ -80,7 +80,6 @@ struct _GstVaapiEncoderMpeg2
/* public */ /* public */
guint32 profile; guint32 profile;
guint32 level; guint32 level;
guint32 bitrate; /*kbps */
guint32 cqp; guint32 cqp;
guint32 intra_period; guint32 intra_period;
guint32 ip_period; guint32 ip_period;

View file

@ -98,6 +98,7 @@ struct _GstVaapiEncoder
GstVideoInfo video_info; GstVideoInfo video_info;
GstVaapiRateControl rate_control; GstVaapiRateControl rate_control;
guint32 rate_control_mask; guint32 rate_control_mask;
guint bitrate; /* kbps */
GMutex mutex; GMutex mutex;
GCond surface_free; GCond surface_free;

View file

@ -318,6 +318,10 @@ ensure_encoder (GstVaapiEncode * encode)
encode->rate_control); encode->rate_control);
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
return FALSE; return FALSE;
status = gst_vaapi_encoder_set_bitrate (encode->encoder, encode->bitrate);
if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
return FALSE;
return TRUE; return TRUE;
} }

View file

@ -162,7 +162,6 @@ gst_vaapiencode_h264_create_encoder (GstVaapiEncode * base,
GstVaapiDisplay * display) GstVaapiDisplay * display)
{ {
GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base); GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base);
GstVaapiEncode *const base_encode = GST_VAAPIENCODE_CAST (base);
GstVaapiEncoder *base_encoder; GstVaapiEncoder *base_encoder;
GstVaapiEncoderH264 *encoder; GstVaapiEncoderH264 *encoder;
@ -173,7 +172,6 @@ gst_vaapiencode_h264_create_encoder (GstVaapiEncode * base,
encoder->profile = GST_VAAPI_PROFILE_UNKNOWN; encoder->profile = GST_VAAPI_PROFILE_UNKNOWN;
encoder->level = GST_VAAPI_ENCODER_H264_DEFAULT_LEVEL; encoder->level = GST_VAAPI_ENCODER_H264_DEFAULT_LEVEL;
encoder->bitrate = base_encode->bitrate;
encoder->intra_period = encode->intra_period; encoder->intra_period = encode->intra_period;
encoder->init_qp = encode->init_qp; encoder->init_qp = encode->init_qp;
encoder->min_qp = encode->min_qp; encoder->min_qp = encode->min_qp;

View file

@ -153,7 +153,6 @@ gst_vaapiencode_mpeg2_create_encoder (GstVaapiEncode * base,
GstVaapiDisplay * display) GstVaapiDisplay * display)
{ {
GstVaapiEncodeMpeg2 *const encode = GST_VAAPIENCODE_MPEG2_CAST (base); GstVaapiEncodeMpeg2 *const encode = GST_VAAPIENCODE_MPEG2_CAST (base);
GstVaapiEncode *const base_encode = GST_VAAPIENCODE_CAST (base);
GstVaapiEncoder *base_encoder; GstVaapiEncoder *base_encoder;
GstVaapiEncoderMpeg2 *encoder; GstVaapiEncoderMpeg2 *encoder;
@ -164,7 +163,6 @@ gst_vaapiencode_mpeg2_create_encoder (GstVaapiEncode * base,
encoder->profile = GST_VAAPI_ENCODER_MPEG2_DEFAULT_PROFILE; encoder->profile = GST_VAAPI_ENCODER_MPEG2_DEFAULT_PROFILE;
encoder->level = GST_VAAPI_ENCODER_MPEG2_DEFAULT_LEVEL; encoder->level = GST_VAAPI_ENCODER_MPEG2_DEFAULT_LEVEL;
encoder->bitrate = base_encode->bitrate;
encoder->cqp = encode->quantizer; encoder->cqp = encode->quantizer;
encoder->intra_period = encode->intra_period; encoder->intra_period = encode->intra_period;
encoder->ip_period = encode->ip_period; encoder->ip_period = encode->ip_period;