diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index 5af378487f..8b2c9ee179 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -67,14 +67,14 @@ GST_STATIC_PAD_TEMPLATE ("sink", 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_stop (GstAudioDecoder * dec); static GstFlowReturn gst_opus_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer); static gboolean gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps); -static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, - GstBuffer * buf, GstClockTime timestamp, GstClockTime duration); static void gst_opus_dec_class_init (GstOpusDecClass * klass) @@ -112,8 +112,6 @@ gst_opus_dec_reset (GstOpusDec * dec) dec->state = NULL; } - dec->next_ts = 0; - gst_buffer_replace (&dec->streamheader, NULL); gst_buffer_replace (&dec->vorbiscomment, NULL); } @@ -167,17 +165,19 @@ gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec) { GstPad *srcpad, *peer; 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); peer = gst_pad_get_peer (srcpad); if (peer) { 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); 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); s = gst_caps_get_structure (caps, 0); @@ -203,8 +203,7 @@ gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec) } static GstFlowReturn -opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf, - GstClockTime timestamp, GstClockTime duration) +opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; gsize size, out_size; @@ -218,6 +217,8 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf, if (dec->state == NULL) { 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); if (!dec->state || err != OPUS_OK) 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); GST_DEBUG_OBJECT (dec, "received buffer of size %u", size); - - /* copy timestamp */ } else { /* concealment data, pass NULL as the bits parameters */ 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); - 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); 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); res = GST_FLOW_OK; } else { - res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), - GST_BUFFER_DURATION (buf)); + res = opus_dec_chain_parse_data (dec, buf); } } else { /* 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); gst_audio_decoder_finish_frame (adec, NULL, 1); } else { - res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), - GST_BUFFER_DURATION (buf)); + res = opus_dec_chain_parse_data (dec, buf); } break; case 1: @@ -418,14 +401,12 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf) res = gst_opus_dec_parse_comments (dec, buf); gst_audio_decoder_finish_frame (adec, NULL, 1); } else { - res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), - GST_BUFFER_DURATION (buf)); + res = opus_dec_chain_parse_data (dec, buf); } break; default: { - res = opus_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf), - GST_BUFFER_DURATION (buf)); + res = opus_dec_chain_parse_data (dec, buf); break; } } diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index 38dd2799ad..9e78330e1f 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -47,7 +47,6 @@ struct _GstOpusDec { OpusDecoder *state; guint64 packetno; - GstClockTime next_ts; GstBuffer *streamheader; GstBuffer *vorbiscomment; diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 4ef0ffdbe8..cb9615a650 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -94,9 +94,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-opus, " - "rate = (int) { 8000, 12000, 16000, 24000, 48000 }, " - "channels = (int) [ 1, 2 ], " "frame-size = (int) [ 2, 60 ]") + GST_STATIC_CAPS ("audio/x-opus") ); #define DEFAULT_AUDIO TRUE @@ -144,6 +142,9 @@ static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf); static GstFlowReturn gst_opus_enc_pre_push (GstAudioEncoder * benc, 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 gint64 gst_opus_enc_get_latency (GstOpusEnc * enc); @@ -157,13 +158,16 @@ static void gst_opus_enc_class_init (GstOpusEncClass * klass) { GObjectClass *gobject_class; - GstElementClass *element_class; + GstElementClass *gstelement_class; GstAudioEncoderClass *base_class; gobject_class = (GObjectClass *) klass; - element_class = (GstElementClass *) klass; + gstelement_class = (GstElementClass *) 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_static_pad_template_get (&src_factory)); 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->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_param_spec_boolean ("audio", "Audio or voice", "Audio or voice", DEFAULT_AUDIO, @@ -205,7 +206,7 @@ gst_opus_enc_class_init (GstOpusEncClass * klass) "Constant bit rate", DEFAULT_CBR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_COMPLEXITY, @@ -237,12 +238,11 @@ gst_opus_enc_finalize (GObject * object) enc = GST_OPUS_ENC (object); - GST_DEBUG_OBJECT (enc, "finalize"); G_OBJECT_CLASS (parent_class)->finalize (object); } static void -gst_opus_enc_init (GstOpusEnc * enc) +gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass) { GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc); @@ -273,7 +273,7 @@ gst_opus_enc_start (GstAudioEncoder * benc) GstOpusEnc *enc = GST_OPUS_ENC (benc); GST_DEBUG_OBJECT (enc, "start"); - enc->tags = gst_tag_list_new_empty (); + enc->tags = gst_tag_list_new (); enc->header_sent = FALSE; return TRUE; } @@ -297,6 +297,15 @@ gst_opus_enc_stop (GstAudioEncoder * benc) 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 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); enc->state = NULL; } - if (!gst_opus_enc_setup (enc)) return FALSE; @@ -354,7 +362,6 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) /* feedback to base class */ gst_audio_encoder_set_latency (benc, gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc)); - gst_audio_encoder_set_frame_samples_min (benc, enc->frame_samples * enc->n_channels * 2); gst_audio_encoder_set_frame_samples_max (benc, @@ -364,15 +371,6 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) 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 * gst_opus_enc_create_id_buffer (GstOpusEnc * enc) { @@ -495,8 +493,8 @@ gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event) static GstFlowReturn gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer) { - GstOpusEnc *enc; GstFlowReturn ret = GST_FLOW_OK; + GstOpusEnc *enc; enc = GST_OPUS_ENC (benc); @@ -522,6 +520,39 @@ gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer) 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 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; enc = GST_OPUS_ENC (benc); - GST_DEBUG_OBJECT (enc, "handle_frame"); 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); /* mark and put on caps */ - caps = - 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_from_string ("audio/x-opus"); caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL); /* negotiate with these 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_caps_unref (caps); /* push out buffers */ /* 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"); enc->headers = g_slist_prepend (enc->headers, buf2); enc->headers = g_slist_prepend (enc->headers, buf1); - enc->header_sent = TRUE; } 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); diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h index 5d4e3c4008..fe7b94e68d 100644 --- a/ext/opus/gstopusenc.h +++ b/ext/opus/gstopusenc.h @@ -48,11 +48,7 @@ typedef struct _GstOpusEnc GstOpusEnc; typedef struct _GstOpusEncClass GstOpusEncClass; struct _GstOpusEnc { - GstAudioEncoder element; - - /* pads */ - GstPad *sinkpad; - GstPad *srcpad; + GstAudioEncoder element; OpusEncoder *state; @@ -74,7 +70,8 @@ struct _GstOpusEnc { gboolean setup; gboolean header_sent; - GSList *headers; + + GSList *headers; GstTagList *tags; };