Merge branch 'master' into 0.11

Conflicts:
	ext/celt/gstceltdec.c
	ext/opus/gstopusdec.c
	ext/opus/gstopusdec.h
	ext/opus/gstopusenc.c
	ext/opus/gstopusenc.h
	ext/opus/gstopusparse.c
This commit is contained in:
Wim Taymans 2011-11-17 17:32:42 +01:00
commit f566dae7dc
4 changed files with 74 additions and 72 deletions

View file

@ -67,14 +67,14 @@ GST_STATIC_PAD_TEMPLATE ("sink",
G_DEFINE_TYPE (GstOpusDec, gst_opus_dec, GST_TYPE_AUDIO_DECODER); G_DEFINE_TYPE (GstOpusDec, gst_opus_dec, GST_TYPE_AUDIO_DECODER);
static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec,
GstBuffer * buf);
static gboolean gst_opus_dec_start (GstAudioDecoder * dec); static gboolean gst_opus_dec_start (GstAudioDecoder * dec);
static gboolean gst_opus_dec_stop (GstAudioDecoder * dec); static gboolean gst_opus_dec_stop (GstAudioDecoder * dec);
static GstFlowReturn gst_opus_dec_handle_frame (GstAudioDecoder * dec, static GstFlowReturn gst_opus_dec_handle_frame (GstAudioDecoder * dec,
GstBuffer * buffer); GstBuffer * buffer);
static gboolean gst_opus_dec_set_format (GstAudioDecoder * bdec, static gboolean gst_opus_dec_set_format (GstAudioDecoder * bdec,
GstCaps * caps); GstCaps * caps);
static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec,
GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
static void static void
gst_opus_dec_class_init (GstOpusDecClass * klass) gst_opus_dec_class_init (GstOpusDecClass * klass)
@ -112,8 +112,6 @@ gst_opus_dec_reset (GstOpusDec * dec)
dec->state = NULL; dec->state = NULL;
} }
dec->next_ts = 0;
gst_buffer_replace (&dec->streamheader, NULL); gst_buffer_replace (&dec->streamheader, NULL);
gst_buffer_replace (&dec->vorbiscomment, NULL); gst_buffer_replace (&dec->vorbiscomment, NULL);
} }
@ -167,17 +165,19 @@ gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec)
{ {
GstPad *srcpad, *peer; GstPad *srcpad, *peer;
GstStructure *s; GstStructure *s;
GstCaps *caps, *template_caps, *peer_caps; GstCaps *caps;
const GstCaps *template_caps;
const GstCaps *peer_caps;
srcpad = GST_AUDIO_DECODER_SRC_PAD (dec); srcpad = GST_AUDIO_DECODER_SRC_PAD (dec);
peer = gst_pad_get_peer (srcpad); peer = gst_pad_get_peer (srcpad);
if (peer) { if (peer) {
template_caps = gst_pad_get_pad_template_caps (srcpad); template_caps = gst_pad_get_pad_template_caps (srcpad);
peer_caps = gst_pad_get_caps (peer, NULL); peer_caps = gst_pad_get_caps (peer);
GST_DEBUG_OBJECT (dec, "Peer caps: %" GST_PTR_FORMAT, peer_caps); GST_DEBUG_OBJECT (dec, "Peer caps: %" GST_PTR_FORMAT, peer_caps);
caps = gst_caps_intersect (template_caps, peer_caps); caps = gst_caps_intersect (template_caps, peer_caps);
gst_caps_fixate (caps); gst_pad_fixate_caps (peer, caps);
GST_DEBUG_OBJECT (dec, "Fixated caps: %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (dec, "Fixated caps: %" GST_PTR_FORMAT, caps);
s = gst_caps_get_structure (caps, 0); s = gst_caps_get_structure (caps, 0);
@ -203,8 +203,7 @@ gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec)
} }
static GstFlowReturn static GstFlowReturn
opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf, opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf)
GstClockTime timestamp, GstClockTime duration)
{ {
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res = GST_FLOW_OK;
gsize size, out_size; gsize size, out_size;
@ -218,6 +217,8 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
if (dec->state == NULL) { if (dec->state == NULL) {
gst_opus_dec_setup_from_peer_caps (dec); gst_opus_dec_setup_from_peer_caps (dec);
GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz",
dec->n_channels, dec->sample_rate);
dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels, &err); dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels, &err);
if (!dec->state || err != OPUS_OK) if (!dec->state || err != OPUS_OK)
goto creation_failed; goto creation_failed;
@ -227,8 +228,6 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
GST_DEBUG_OBJECT (dec, "received buffer of size %u", size); GST_DEBUG_OBJECT (dec, "received buffer of size %u", size);
/* copy timestamp */
} else { } else {
/* concealment data, pass NULL as the bits parameters */ /* concealment data, pass NULL as the bits parameters */
GST_DEBUG_OBJECT (dec, "creating concealment data"); GST_DEBUG_OBJECT (dec, "creating concealment data");
@ -261,20 +260,6 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
} }
GST_DEBUG_OBJECT (dec, "decoded %d samples", n); GST_DEBUG_OBJECT (dec, "decoded %d samples", n);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
} else {
GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
}
GST_BUFFER_DURATION (outbuf) =
gst_util_uint64_scale (n, GST_SECOND, dec->sample_rate);
dec->next_ts = GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf);
GST_LOG_OBJECT (dec, "pushing buffer with ts=%" GST_TIME_FORMAT ", dur=%"
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
if (res != GST_FLOW_OK) if (res != GST_FLOW_OK)
@ -395,8 +380,7 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
gst_audio_decoder_finish_frame (adec, NULL, 1); gst_audio_decoder_finish_frame (adec, NULL, 1);
res = GST_FLOW_OK; res = GST_FLOW_OK;
} else { } else {
res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), res = opus_dec_chain_parse_data (dec, buf);
GST_BUFFER_DURATION (buf));
} }
} else { } else {
/* Otherwise fall back to packet counting and assume that the /* Otherwise fall back to packet counting and assume that the
@ -408,8 +392,7 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
res = gst_opus_dec_parse_header (dec, buf); res = gst_opus_dec_parse_header (dec, buf);
gst_audio_decoder_finish_frame (adec, NULL, 1); gst_audio_decoder_finish_frame (adec, NULL, 1);
} else { } else {
res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), res = opus_dec_chain_parse_data (dec, buf);
GST_BUFFER_DURATION (buf));
} }
break; break;
case 1: case 1:
@ -418,14 +401,12 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
res = gst_opus_dec_parse_comments (dec, buf); res = gst_opus_dec_parse_comments (dec, buf);
gst_audio_decoder_finish_frame (adec, NULL, 1); gst_audio_decoder_finish_frame (adec, NULL, 1);
} else { } else {
res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), res = opus_dec_chain_parse_data (dec, buf);
GST_BUFFER_DURATION (buf));
} }
break; break;
default: default:
{ {
res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), res = opus_dec_chain_parse_data (dec, buf);
GST_BUFFER_DURATION (buf));
break; break;
} }
} }

View file

@ -47,7 +47,6 @@ struct _GstOpusDec {
OpusDecoder *state; OpusDecoder *state;
guint64 packetno; guint64 packetno;
GstClockTime next_ts;
GstBuffer *streamheader; GstBuffer *streamheader;
GstBuffer *vorbiscomment; GstBuffer *vorbiscomment;

View file

@ -94,9 +94,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-opus, " GST_STATIC_CAPS ("audio/x-opus")
"rate = (int) { 8000, 12000, 16000, 24000, 48000 }, "
"channels = (int) [ 1, 2 ], " "frame-size = (int) [ 2, 60 ]")
); );
#define DEFAULT_AUDIO TRUE #define DEFAULT_AUDIO TRUE
@ -144,6 +142,9 @@ static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc,
GstBuffer * buf); GstBuffer * buf);
static GstFlowReturn gst_opus_enc_pre_push (GstAudioEncoder * benc, static GstFlowReturn gst_opus_enc_pre_push (GstAudioEncoder * benc,
GstBuffer ** buffer); GstBuffer ** buffer);
static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer);
static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf); static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf);
static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc); static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
@ -157,13 +158,16 @@ static void
gst_opus_enc_class_init (GstOpusEncClass * klass) gst_opus_enc_class_init (GstOpusEncClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *element_class; GstElementClass *gstelement_class;
GstAudioEncoderClass *base_class; GstAudioEncoderClass *base_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
element_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
base_class = (GstAudioEncoderClass *) klass; base_class = (GstAudioEncoderClass *) klass;
gobject_class->set_property = gst_opus_enc_set_property;
gobject_class->get_property = gst_opus_enc_get_property;
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory)); gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
@ -180,9 +184,6 @@ gst_opus_enc_class_init (GstOpusEncClass * klass)
base_class->pre_push = GST_DEBUG_FUNCPTR (gst_opus_enc_pre_push); base_class->pre_push = GST_DEBUG_FUNCPTR (gst_opus_enc_pre_push);
base_class->event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event); base_class->event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
gobject_class->set_property = gst_opus_enc_set_property;
gobject_class->get_property = gst_opus_enc_get_property;
g_object_class_install_property (gobject_class, PROP_AUDIO, g_object_class_install_property (gobject_class, PROP_AUDIO,
g_param_spec_boolean ("audio", "Audio or voice", g_param_spec_boolean ("audio", "Audio or voice",
"Audio or voice", DEFAULT_AUDIO, "Audio or voice", DEFAULT_AUDIO,
@ -205,7 +206,7 @@ gst_opus_enc_class_init (GstOpusEncClass * klass)
"Constant bit rate", DEFAULT_CBR, "Constant bit rate", DEFAULT_CBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CONSTRAINED_VBR, g_object_class_install_property (gobject_class, PROP_CONSTRAINED_VBR,
g_param_spec_boolean ("constrained-cbr", "Constrained VBR", g_param_spec_boolean ("constrained-vbr", "Constrained VBR",
"Constrained VBR", DEFAULT_CONSTRAINED_VBR, "Constrained VBR", DEFAULT_CONSTRAINED_VBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_COMPLEXITY, g_object_class_install_property (gobject_class, PROP_COMPLEXITY,
@ -237,12 +238,11 @@ gst_opus_enc_finalize (GObject * object)
enc = GST_OPUS_ENC (object); enc = GST_OPUS_ENC (object);
GST_DEBUG_OBJECT (enc, "finalize");
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static void static void
gst_opus_enc_init (GstOpusEnc * enc) gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass)
{ {
GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc); GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
@ -273,7 +273,7 @@ gst_opus_enc_start (GstAudioEncoder * benc)
GstOpusEnc *enc = GST_OPUS_ENC (benc); GstOpusEnc *enc = GST_OPUS_ENC (benc);
GST_DEBUG_OBJECT (enc, "start"); GST_DEBUG_OBJECT (enc, "start");
enc->tags = gst_tag_list_new_empty (); enc->tags = gst_tag_list_new ();
enc->header_sent = FALSE; enc->header_sent = FALSE;
return TRUE; return TRUE;
} }
@ -297,6 +297,15 @@ gst_opus_enc_stop (GstAudioEncoder * benc)
return TRUE; return TRUE;
} }
static gint64
gst_opus_enc_get_latency (GstOpusEnc * enc)
{
gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND,
enc->sample_rate);
GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
return latency;
}
static gint static gint
gst_opus_enc_get_frame_samples (GstOpusEnc * enc) gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
{ {
@ -345,7 +354,6 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
opus_encoder_destroy (enc->state); opus_encoder_destroy (enc->state);
enc->state = NULL; enc->state = NULL;
} }
if (!gst_opus_enc_setup (enc)) if (!gst_opus_enc_setup (enc))
return FALSE; return FALSE;
@ -354,7 +362,6 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
/* feedback to base class */ /* feedback to base class */
gst_audio_encoder_set_latency (benc, gst_audio_encoder_set_latency (benc,
gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc)); gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
gst_audio_encoder_set_frame_samples_min (benc, gst_audio_encoder_set_frame_samples_min (benc,
enc->frame_samples * enc->n_channels * 2); enc->frame_samples * enc->n_channels * 2);
gst_audio_encoder_set_frame_samples_max (benc, gst_audio_encoder_set_frame_samples_max (benc,
@ -364,15 +371,6 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
return TRUE; return TRUE;
} }
static gint64
gst_opus_enc_get_latency (GstOpusEnc * enc)
{
gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND,
enc->sample_rate);
GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
return latency;
}
static GstBuffer * static GstBuffer *
gst_opus_enc_create_id_buffer (GstOpusEnc * enc) gst_opus_enc_create_id_buffer (GstOpusEnc * enc)
{ {
@ -495,8 +493,8 @@ gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
static GstFlowReturn static GstFlowReturn
gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer) gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
{ {
GstOpusEnc *enc;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstOpusEnc *enc;
enc = GST_OPUS_ENC (benc); enc = GST_OPUS_ENC (benc);
@ -522,6 +520,39 @@ gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
return ret; return ret;
} }
static GstFlowReturn
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)) {
bdata = GST_BUFFER_DATA (buf);
bsize = GST_BUFFER_SIZE (buf);
if (G_UNLIKELY (bsize % bytes)) {
GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
size = ((bsize / bytes) + 1) * bytes;
mdata = g_malloc0 (size);
memcpy (mdata, bdata, bsize);
bdata = NULL;
data = mdata;
} else {
data = bdata;
size = bsize;
}
} else {
GST_DEBUG_OBJECT (enc, "nothing to drain");
goto done;
}
return ret;
}
static GstFlowReturn static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{ {
@ -669,7 +700,6 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
enc = GST_OPUS_ENC (benc); enc = GST_OPUS_ENC (benc);
GST_DEBUG_OBJECT (enc, "handle_frame"); GST_DEBUG_OBJECT (enc, "handle_frame");
if (!enc->header_sent) { if (!enc->header_sent) {
@ -684,17 +714,13 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
buf2 = gst_opus_enc_create_metadata_buffer (enc); buf2 = gst_opus_enc_create_metadata_buffer (enc);
/* mark and put on caps */ /* mark and put on caps */
caps = caps = gst_caps_from_string ("audio/x-opus");
gst_caps_new_simple ("audio/x-opus", "rate", G_TYPE_INT,
enc->sample_rate, "channels", G_TYPE_INT, enc->n_channels, "frame-size",
G_TYPE_INT, enc->frame_size, NULL);
caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL); caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
/* negotiate with these caps */ /* negotiate with these caps */
GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps); gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
gst_caps_unref (caps);
/* push out buffers */ /* push out buffers */
/* store buffers for later pre_push sending */ /* store buffers for later pre_push sending */
@ -703,12 +729,11 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
GST_DEBUG_OBJECT (enc, "storing header buffers"); GST_DEBUG_OBJECT (enc, "storing header buffers");
enc->headers = g_slist_prepend (enc->headers, buf2); enc->headers = g_slist_prepend (enc->headers, buf2);
enc->headers = g_slist_prepend (enc->headers, buf1); enc->headers = g_slist_prepend (enc->headers, buf1);
enc->header_sent = TRUE; enc->header_sent = TRUE;
} }
GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf, GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
buf ? gst_buffer_get_size (buf) : 0); buf ? GST_BUFFER_SIZE (buf) : 0);
ret = gst_opus_enc_encode (enc, buf); ret = gst_opus_enc_encode (enc, buf);

View file

@ -48,11 +48,7 @@ typedef struct _GstOpusEnc GstOpusEnc;
typedef struct _GstOpusEncClass GstOpusEncClass; typedef struct _GstOpusEncClass GstOpusEncClass;
struct _GstOpusEnc { struct _GstOpusEnc {
GstAudioEncoder element; GstAudioEncoder element;
/* pads */
GstPad *sinkpad;
GstPad *srcpad;
OpusEncoder *state; OpusEncoder *state;
@ -74,7 +70,8 @@ struct _GstOpusEnc {
gboolean setup; gboolean setup;
gboolean header_sent; gboolean header_sent;
GSList *headers;
GSList *headers;
GstTagList *tags; GstTagList *tags;
}; };