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.
This commit is contained in:
Vincent Penquerc'h 2011-11-22 15:33:20 +00:00
parent da5c41930c
commit 49e08a1835
2 changed files with 23 additions and 10 deletions

View file

@ -132,6 +132,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
#define DEFAULT_INBAND_FEC FALSE #define DEFAULT_INBAND_FEC FALSE
#define DEFAULT_DTX FALSE #define DEFAULT_DTX FALSE
#define DEFAULT_PACKET_LOSS_PERCENT 0 #define DEFAULT_PACKET_LOSS_PERCENT 0
#define DEFAULT_MAX_PAYLOAD_SIZE 1024
enum enum
{ {
@ -145,7 +146,8 @@ enum
PROP_COMPLEXITY, PROP_COMPLEXITY,
PROP_INBAND_FEC, PROP_INBAND_FEC,
PROP_DTX, PROP_DTX,
PROP_PACKET_LOSS_PERCENT PROP_PACKET_LOSS_PERCENT,
PROP_MAX_PAYLOAD_SIZE
}; };
static void gst_opus_enc_finalize (GObject * object); 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, "Loss percentage", "Packet loss percentage", 0, 100,
DEFAULT_PACKET_LOSS_PERCENT, DEFAULT_PACKET_LOSS_PERCENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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); 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->inband_fec = DEFAULT_INBAND_FEC;
enc->dtx = DEFAULT_DTX; enc->dtx = DEFAULT_DTX;
enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT; enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;
/* arrange granulepos marking (and required perfect ts) */ /* arrange granulepos marking (and required perfect ts) */
gst_audio_encoder_set_mark_granule (benc, TRUE); 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; guint8 *bdata, *data, *mdata = NULL;
gsize bsize, size; gsize bsize, size;
gsize bytes = enc->frame_samples * enc->n_channels * 2; 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; gint ret = GST_FLOW_OK;
if (G_LIKELY (buf)) { if (G_LIKELY (buf)) {
@ -511,27 +517,27 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
GstBuffer *outbuf; GstBuffer *outbuf;
ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), 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); GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
if (GST_FLOW_OK != ret) if (GST_FLOW_OK != ret)
goto done; goto done;
GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes) to %d bytes", GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
enc->frame_samples, bytes, bytes_per_packet); enc->frame_samples);
outsize = outsize =
opus_encode (enc->state, (const gint16 *) data, enc->frame_samples, 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) { if (outsize < 0) {
GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize); GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize);
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto done; goto done;
} else if (outsize > bytes_per_packet) { } else if (outsize > enc->max_payload_size) {
GST_WARNING_OBJECT (enc, GST_WARNING_OBJECT (enc,
"Encoded size %d is different from %d bytes per packet", outsize, "Encoded size %d is higher than max payload size (%d bytes)",
bytes_per_packet); outsize, enc->max_payload_size);
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto done; goto done;
} }
@ -631,6 +637,9 @@ gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_PACKET_LOSS_PERCENT: case PROP_PACKET_LOSS_PERCENT:
g_value_set_int (value, enc->packet_loss_percentage); g_value_set_int (value, enc->packet_loss_percentage);
break; break;
case PROP_MAX_PAYLOAD_SIZE:
g_value_set_uint (value, enc->max_payload_size);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -676,6 +685,9 @@ gst_opus_enc_set_property (GObject * object, guint prop_id,
case PROP_PACKET_LOSS_PERCENT: case PROP_PACKET_LOSS_PERCENT:
enc->packet_loss_percentage = g_value_get_int (value); enc->packet_loss_percentage = g_value_get_int (value);
break; break;
case PROP_MAX_PAYLOAD_SIZE:
enc->max_payload_size = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -63,6 +63,7 @@ struct _GstOpusEnc {
gboolean inband_fec; gboolean inband_fec;
gboolean dtx; gboolean dtx;
gint packet_loss_percentage; gint packet_loss_percentage;
guint max_payload_size;
gint frame_samples; gint frame_samples;
gint n_channels; gint n_channels;