From bb39c86fdfff4674a023de3ae193db68141a80e4 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 22 Nov 2011 15:33:20 +0000 Subject: [PATCH] opusenc: fix crash on pathological parameters Asking for 1 bit/s would select a 0 byte buffer, leading to a crash. Buffer size is now controlled by a max-payload-size property, which can't be less than 2. --- ext/opus/gstopusenc.c | 32 ++++++++++++++++++++++---------- ext/opus/gstopusenc.h | 1 + 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 276e1ddaa1..6a7d549bd6 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -132,6 +132,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", #define DEFAULT_INBAND_FEC FALSE #define DEFAULT_DTX FALSE #define DEFAULT_PACKET_LOSS_PERCENT 0 +#define DEFAULT_MAX_PAYLOAD_SIZE 1024 enum { @@ -145,7 +146,8 @@ enum PROP_COMPLEXITY, PROP_INBAND_FEC, PROP_DTX, - PROP_PACKET_LOSS_PERCENT + PROP_PACKET_LOSS_PERCENT, + PROP_MAX_PAYLOAD_SIZE }; static void gst_opus_enc_finalize (GObject * object); @@ -267,6 +269,11 @@ gst_opus_enc_class_init (GstOpusEncClass * klass) "Loss percentage", "Packet loss percentage", 0, 100, DEFAULT_PACKET_LOSS_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size", + "Max payload size", "Maximum payload size in bytes", 2, 1275, + DEFAULT_MAX_PAYLOAD_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize); } @@ -301,6 +308,7 @@ gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass) enc->inband_fec = DEFAULT_INBAND_FEC; enc->dtx = DEFAULT_DTX; enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT; + enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE; /* arrange granulepos marking (and required perfect ts) */ gst_audio_encoder_set_mark_granule (benc, TRUE); @@ -481,8 +489,6 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) guint8 *bdata, *data, *mdata = NULL; gsize bsize, size; gsize bytes = enc->frame_samples * enc->n_channels * 2; - gsize bytes_per_packet = - (enc->bitrate * enc->frame_samples / enc->sample_rate + 4) / 8; gint ret = GST_FLOW_OK; if (G_LIKELY (buf)) { @@ -511,27 +517,27 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) GstBuffer *outbuf; ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), - GST_BUFFER_OFFSET_NONE, bytes_per_packet, + GST_BUFFER_OFFSET_NONE, enc->max_payload_size, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf); if (GST_FLOW_OK != ret) goto done; - GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes) to %d bytes", - enc->frame_samples, bytes, bytes_per_packet); + GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", + enc->frame_samples); outsize = opus_encode (enc->state, (const gint16 *) data, enc->frame_samples, - GST_BUFFER_DATA (outbuf), bytes_per_packet); + GST_BUFFER_DATA (outbuf), enc->max_payload_size); if (outsize < 0) { GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize); ret = GST_FLOW_ERROR; goto done; - } else if (outsize > bytes_per_packet) { + } else if (outsize > enc->max_payload_size) { GST_WARNING_OBJECT (enc, - "Encoded size %d is different from %d bytes per packet", outsize, - bytes_per_packet); + "Encoded size %d is higher than max payload size (%d bytes)", + outsize, enc->max_payload_size); ret = GST_FLOW_ERROR; goto done; } @@ -631,6 +637,9 @@ gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_PACKET_LOSS_PERCENT: g_value_set_int (value, enc->packet_loss_percentage); break; + case PROP_MAX_PAYLOAD_SIZE: + g_value_set_uint (value, enc->max_payload_size); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -676,6 +685,9 @@ gst_opus_enc_set_property (GObject * object, guint prop_id, case PROP_PACKET_LOSS_PERCENT: enc->packet_loss_percentage = g_value_get_int (value); break; + case PROP_MAX_PAYLOAD_SIZE: + enc->max_payload_size = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h index fe7b94e68d..d645ce8d07 100644 --- a/ext/opus/gstopusenc.h +++ b/ext/opus/gstopusenc.h @@ -63,6 +63,7 @@ struct _GstOpusEnc { gboolean inband_fec; gboolean dtx; gint packet_loss_percentage; + guint max_payload_size; gint frame_samples; gint n_channels;