• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer Opus Encoder
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  * Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /*
23  * Based on the speexenc element
24  */
25 
26 /**
27  * SECTION:element-opusenc
28  * @title: opusenc
29  * @see_also: opusdec, oggmux
30  *
31  * This element encodes raw audio to OPUS.
32  *
33  * ## Example pipelines
34  * |[
35  * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! opusenc ! oggmux ! filesink location=sine.ogg
36  * ]|
37  * Encode a test sine signal to Ogg/OPUS.
38  *
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <math.h>
48 #include <opus.h>
49 
50 #include <gst/gsttagsetter.h>
51 #include <gst/audio/audio.h>
52 #include <gst/pbutils/pbutils.h>
53 #include <gst/tag/tag.h>
54 #include <gst/glib-compat-private.h>
55 
56 #include "gstopuselements.h"
57 #include "gstopusheader.h"
58 #include "gstopuscommon.h"
59 #include "gstopusenc.h"
60 
61 GST_DEBUG_CATEGORY_STATIC (opusenc_debug);
62 #define GST_CAT_DEFAULT opusenc_debug
63 
64 /* Some arbitrary bounds beyond which it really doesn't make sense.
65    The spec mentions 6 kb/s to 510 kb/s, so 4000 and 650000 ought to be
66    safe as property bounds. */
67 #define LOWEST_BITRATE 4000
68 #define HIGHEST_BITRATE 650000
69 
70 #define GST_OPUS_ENC_TYPE_BANDWIDTH (gst_opus_enc_bandwidth_get_type())
71 static GType
gst_opus_enc_bandwidth_get_type(void)72 gst_opus_enc_bandwidth_get_type (void)
73 {
74   static const GEnumValue values[] = {
75     {OPUS_BANDWIDTH_NARROWBAND, "Narrow band", "narrowband"},
76     {OPUS_BANDWIDTH_MEDIUMBAND, "Medium band", "mediumband"},
77     {OPUS_BANDWIDTH_WIDEBAND, "Wide band", "wideband"},
78     {OPUS_BANDWIDTH_SUPERWIDEBAND, "Super wide band", "superwideband"},
79     {OPUS_BANDWIDTH_FULLBAND, "Full band", "fullband"},
80     {OPUS_AUTO, "Auto", "auto"},
81     {0, NULL, NULL}
82   };
83   static GType id = 0;
84 
85   if (g_once_init_enter ((gsize *) & id)) {
86     GType _id;
87 
88     _id = g_enum_register_static ("GstOpusEncBandwidth", values);
89 
90     g_once_init_leave ((gsize *) & id, _id);
91   }
92 
93   return id;
94 }
95 
96 #define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type())
97 static GType
gst_opus_enc_frame_size_get_type(void)98 gst_opus_enc_frame_size_get_type (void)
99 {
100   static const GEnumValue values[] = {
101     {2, "2.5", "2.5"},
102     {5, "5", "5"},
103     {10, "10", "10"},
104     {20, "20", "20"},
105     {40, "40", "40"},
106     {60, "60", "60"},
107     {0, NULL, NULL}
108   };
109   static GType id = 0;
110 
111   if (g_once_init_enter ((gsize *) & id)) {
112     GType _id;
113 
114     _id = g_enum_register_static ("GstOpusEncFrameSize", values);
115 
116     g_once_init_leave ((gsize *) & id, _id);
117   }
118 
119   return id;
120 }
121 
122 #define GST_OPUS_ENC_TYPE_AUDIO_TYPE (gst_opus_enc_audio_type_get_type())
123 static GType
gst_opus_enc_audio_type_get_type(void)124 gst_opus_enc_audio_type_get_type (void)
125 {
126   static const GEnumValue values[] = {
127     {OPUS_APPLICATION_AUDIO, "Generic audio", "generic"},
128     {OPUS_APPLICATION_VOIP, "Voice", "voice"},
129     {OPUS_APPLICATION_RESTRICTED_LOWDELAY, "Restricted low delay",
130         "restricted-lowdelay"},
131     {0, NULL, NULL}
132   };
133   static GType id = 0;
134 
135   if (g_once_init_enter ((gsize *) & id)) {
136     GType _id;
137 
138     _id = g_enum_register_static ("GstOpusEncAudioType", values);
139 
140     g_once_init_leave ((gsize *) & id, _id);
141   }
142 
143   return id;
144 }
145 
146 #define GST_OPUS_ENC_TYPE_BITRATE_TYPE (gst_opus_enc_bitrate_type_get_type())
147 static GType
gst_opus_enc_bitrate_type_get_type(void)148 gst_opus_enc_bitrate_type_get_type (void)
149 {
150   static const GEnumValue values[] = {
151     {BITRATE_TYPE_CBR, "CBR", "cbr"},
152     {BITRATE_TYPE_VBR, "VBR", "vbr"},
153     {BITRATE_TYPE_CONSTRAINED_VBR, "Constrained VBR", "constrained-vbr"},
154     {0, NULL, NULL}
155   };
156   static GType id = 0;
157 
158   if (g_once_init_enter ((gsize *) & id)) {
159     GType _id;
160 
161     _id = g_enum_register_static ("GstOpusEncBitrateType", values);
162 
163     g_once_init_leave ((gsize *) & id, _id);
164   }
165 
166   return id;
167 }
168 
169 #define FORMAT_STR GST_AUDIO_NE(S16)
170 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
171     GST_PAD_SINK,
172     GST_PAD_ALWAYS,
173     GST_STATIC_CAPS ("audio/x-raw, "
174         "format = (string) " FORMAT_STR ", "
175         "layout = (string) interleaved, "
176         "rate = (int) 48000, "
177         "channels = (int) [ 1, 8 ]; "
178         "audio/x-raw, "
179         "format = (string) " FORMAT_STR ", "
180         "layout = (string) interleaved, "
181         "rate = (int) { 8000, 12000, 16000, 24000 }, "
182         "channels = (int) [ 1, 8 ] ")
183     );
184 
185 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
186     GST_PAD_SRC,
187     GST_PAD_ALWAYS,
188     GST_STATIC_CAPS ("audio/x-opus")
189     );
190 
191 #define DEFAULT_AUDIO           TRUE
192 #define DEFAULT_AUDIO_TYPE      OPUS_APPLICATION_AUDIO
193 #define DEFAULT_BITRATE         64000
194 #define DEFAULT_BANDWIDTH       OPUS_BANDWIDTH_FULLBAND
195 #define DEFAULT_FRAMESIZE       20
196 #define DEFAULT_CBR             TRUE
197 #define DEFAULT_CONSTRAINED_VBR TRUE
198 #define DEFAULT_BITRATE_TYPE    BITRATE_TYPE_CBR
199 #define DEFAULT_COMPLEXITY      10
200 #define DEFAULT_INBAND_FEC      FALSE
201 #define DEFAULT_DTX             FALSE
202 #define DEFAULT_PACKET_LOSS_PERCENT 0
203 #define DEFAULT_MAX_PAYLOAD_SIZE 4000
204 
205 enum
206 {
207   PROP_0,
208   PROP_AUDIO_TYPE,
209   PROP_BITRATE,
210   PROP_BANDWIDTH,
211   PROP_FRAME_SIZE,
212   PROP_BITRATE_TYPE,
213   PROP_COMPLEXITY,
214   PROP_INBAND_FEC,
215   PROP_DTX,
216   PROP_PACKET_LOSS_PERCENT,
217   PROP_MAX_PAYLOAD_SIZE
218 };
219 
220 static void gst_opus_enc_finalize (GObject * object);
221 
222 static gboolean gst_opus_enc_sink_event (GstAudioEncoder * benc,
223     GstEvent * event);
224 static GstCaps *gst_opus_enc_sink_getcaps (GstAudioEncoder * benc,
225     GstCaps * filter);
226 static gboolean gst_opus_enc_setup (GstOpusEnc * enc);
227 
228 static void gst_opus_enc_get_property (GObject * object, guint prop_id,
229     GValue * value, GParamSpec * pspec);
230 static void gst_opus_enc_set_property (GObject * object, guint prop_id,
231     const GValue * value, GParamSpec * pspec);
232 
233 static void gst_opus_enc_set_tags (GstOpusEnc * enc);
234 static gboolean gst_opus_enc_start (GstAudioEncoder * benc);
235 static gboolean gst_opus_enc_stop (GstAudioEncoder * benc);
236 static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc,
237     GstAudioInfo * info);
238 static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc,
239     GstBuffer * buf);
240 static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
241 
242 static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer);
243 
244 #define gst_opus_enc_parent_class parent_class
245 G_DEFINE_TYPE_WITH_CODE (GstOpusEnc, gst_opus_enc, GST_TYPE_AUDIO_ENCODER,
246     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
247     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
248 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (opusenc, "opusenc",
249     GST_RANK_PRIMARY, GST_TYPE_OPUS_ENC, opus_element_init (plugin));
250 
251 static void
gst_opus_enc_set_tags(GstOpusEnc * enc)252 gst_opus_enc_set_tags (GstOpusEnc * enc)
253 {
254   GstTagList *taglist;
255 
256   /* create a taglist and add a bitrate tag to it */
257   taglist = gst_tag_list_new_empty ();
258   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
259       GST_TAG_BITRATE, enc->bitrate, NULL);
260 
261   gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (enc), taglist,
262       GST_TAG_MERGE_REPLACE);
263 
264   gst_tag_list_unref (taglist);
265 }
266 
267 static void
gst_opus_enc_class_init(GstOpusEncClass * klass)268 gst_opus_enc_class_init (GstOpusEncClass * klass)
269 {
270   GObjectClass *gobject_class;
271   GstAudioEncoderClass *base_class;
272   GstElementClass *gstelement_class;
273 
274   gobject_class = (GObjectClass *) klass;
275   base_class = (GstAudioEncoderClass *) klass;
276   gstelement_class = (GstElementClass *) klass;
277 
278   gobject_class->set_property = gst_opus_enc_set_property;
279   gobject_class->get_property = gst_opus_enc_get_property;
280 
281   gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
282   gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
283   gst_element_class_set_static_metadata (gstelement_class, "Opus audio encoder",
284       "Codec/Encoder/Audio",
285       "Encodes audio in Opus format",
286       "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>");
287 
288   base_class->start = GST_DEBUG_FUNCPTR (gst_opus_enc_start);
289   base_class->stop = GST_DEBUG_FUNCPTR (gst_opus_enc_stop);
290   base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format);
291   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame);
292   base_class->sink_event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
293   base_class->getcaps = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_getcaps);
294 
295   g_object_class_install_property (gobject_class, PROP_AUDIO_TYPE,
296       g_param_spec_enum ("audio-type", "What type of audio to optimize for",
297           "What type of audio to optimize for", GST_OPUS_ENC_TYPE_AUDIO_TYPE,
298           DEFAULT_AUDIO_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
300       g_param_spec_int ("bitrate", "Encoding Bit-rate",
301           "Specify an encoding bit-rate (in bps).", LOWEST_BITRATE,
302           HIGHEST_BITRATE, DEFAULT_BITRATE,
303           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
304           GST_PARAM_MUTABLE_PLAYING));
305   g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
306       g_param_spec_enum ("bandwidth", "Band Width", "Audio Band Width",
307           GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH,
308           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
309           GST_PARAM_MUTABLE_PLAYING));
310   g_object_class_install_property (gobject_class, PROP_FRAME_SIZE,
311       g_param_spec_enum ("frame-size", "Frame Size",
312           "The duration of an audio frame, in ms", GST_OPUS_ENC_TYPE_FRAME_SIZE,
313           DEFAULT_FRAMESIZE,
314           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
315           GST_PARAM_MUTABLE_PLAYING));
316   g_object_class_install_property (gobject_class, PROP_BITRATE_TYPE,
317       g_param_spec_enum ("bitrate-type", "Bitrate type", "Bitrate type",
318           GST_OPUS_ENC_TYPE_BITRATE_TYPE, DEFAULT_BITRATE_TYPE,
319           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
320           GST_PARAM_MUTABLE_PLAYING));
321   g_object_class_install_property (gobject_class, PROP_COMPLEXITY,
322       g_param_spec_int ("complexity", "Complexity", "Complexity", 0, 10,
323           DEFAULT_COMPLEXITY,
324           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
325           GST_PARAM_MUTABLE_PLAYING));
326   g_object_class_install_property (gobject_class, PROP_INBAND_FEC,
327       g_param_spec_boolean ("inband-fec", "In-band FEC",
328           "Enable forward error correction", DEFAULT_INBAND_FEC,
329           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
330           GST_PARAM_MUTABLE_PLAYING));
331   g_object_class_install_property (gobject_class, PROP_DTX,
332       g_param_spec_boolean ("dtx", "DTX", "DTX", DEFAULT_DTX,
333           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
334           GST_PARAM_MUTABLE_PLAYING));
335   g_object_class_install_property (G_OBJECT_CLASS (klass),
336       PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage",
337           "Loss percentage", "Packet loss percentage", 0, 100,
338           DEFAULT_PACKET_LOSS_PERCENT,
339           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
340           GST_PARAM_MUTABLE_PLAYING));
341   g_object_class_install_property (G_OBJECT_CLASS (klass),
342       PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size",
343           "Max payload size", "Maximum payload size in bytes", 2, 4000,
344           DEFAULT_MAX_PAYLOAD_SIZE,
345           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
346           GST_PARAM_MUTABLE_PLAYING));
347 
348   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize);
349 
350   GST_DEBUG_CATEGORY_INIT (opusenc_debug, "opusenc", 0, "Opus encoder");
351 
352   gst_type_mark_as_plugin_api (GST_OPUS_ENC_TYPE_AUDIO_TYPE, 0);
353   gst_type_mark_as_plugin_api (GST_OPUS_ENC_TYPE_BANDWIDTH, 0);
354   gst_type_mark_as_plugin_api (GST_OPUS_ENC_TYPE_BITRATE_TYPE, 0);
355   gst_type_mark_as_plugin_api (GST_OPUS_ENC_TYPE_FRAME_SIZE, 0);
356 }
357 
358 static void
gst_opus_enc_finalize(GObject * object)359 gst_opus_enc_finalize (GObject * object)
360 {
361   GstOpusEnc *enc;
362 
363   enc = GST_OPUS_ENC (object);
364 
365   g_mutex_clear (&enc->property_lock);
366 
367   G_OBJECT_CLASS (parent_class)->finalize (object);
368 }
369 
370 static void
gst_opus_enc_init(GstOpusEnc * enc)371 gst_opus_enc_init (GstOpusEnc * enc)
372 {
373   GST_DEBUG_OBJECT (enc, "init");
374 
375   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
376 
377   g_mutex_init (&enc->property_lock);
378 
379   enc->n_channels = -1;
380   enc->sample_rate = -1;
381   enc->frame_samples = 0;
382   enc->unpositioned = FALSE;
383 
384   enc->bitrate = DEFAULT_BITRATE;
385   enc->bandwidth = DEFAULT_BANDWIDTH;
386   enc->frame_size = DEFAULT_FRAMESIZE;
387   enc->bitrate_type = DEFAULT_BITRATE_TYPE;
388   enc->complexity = DEFAULT_COMPLEXITY;
389   enc->inband_fec = DEFAULT_INBAND_FEC;
390   enc->dtx = DEFAULT_DTX;
391   enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
392   enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;
393   enc->audio_type = DEFAULT_AUDIO_TYPE;
394 }
395 
396 static gboolean
gst_opus_enc_start(GstAudioEncoder * benc)397 gst_opus_enc_start (GstAudioEncoder * benc)
398 {
399   GstOpusEnc *enc = GST_OPUS_ENC (benc);
400 
401   GST_DEBUG_OBJECT (enc, "start");
402   enc->encoded_samples = 0;
403   enc->consumed_samples = 0;
404 
405   return TRUE;
406 }
407 
408 static gboolean
gst_opus_enc_stop(GstAudioEncoder * benc)409 gst_opus_enc_stop (GstAudioEncoder * benc)
410 {
411   GstOpusEnc *enc = GST_OPUS_ENC (benc);
412 
413   GST_DEBUG_OBJECT (enc, "stop");
414   if (enc->state) {
415     opus_multistream_encoder_destroy (enc->state);
416     enc->state = NULL;
417   }
418   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
419 
420   return TRUE;
421 }
422 
423 static gint64
gst_opus_enc_get_latency(GstOpusEnc * enc)424 gst_opus_enc_get_latency (GstOpusEnc * enc)
425 {
426   gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND,
427       enc->sample_rate);
428   GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
429   return latency;
430 }
431 
432 static void
gst_opus_enc_setup_base_class(GstOpusEnc * enc,GstAudioEncoder * benc)433 gst_opus_enc_setup_base_class (GstOpusEnc * enc, GstAudioEncoder * benc)
434 {
435   gst_audio_encoder_set_latency (benc,
436       gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
437   gst_audio_encoder_set_frame_samples_min (benc, enc->frame_samples);
438   gst_audio_encoder_set_frame_samples_max (benc, enc->frame_samples);
439   gst_audio_encoder_set_frame_max (benc, 1);
440 }
441 
442 static gint
gst_opus_enc_get_frame_samples(GstOpusEnc * enc)443 gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
444 {
445   gint frame_samples = 0;
446   switch (enc->frame_size) {
447     case 2:
448       frame_samples = enc->sample_rate / 400;
449       break;
450     case 5:
451       frame_samples = enc->sample_rate / 200;
452       break;
453     case 10:
454       frame_samples = enc->sample_rate / 100;
455       break;
456     case 20:
457       frame_samples = enc->sample_rate / 50;
458       break;
459     case 40:
460       frame_samples = enc->sample_rate / 25;
461       break;
462     case 60:
463       frame_samples = 3 * enc->sample_rate / 50;
464       break;
465     default:
466       GST_WARNING_OBJECT (enc, "Unsupported frame size: %d", enc->frame_size);
467       frame_samples = 0;
468       break;
469   }
470   return frame_samples;
471 }
472 
473 static void
gst_opus_enc_setup_trivial_mapping(GstOpusEnc * enc,guint8 mapping[256])474 gst_opus_enc_setup_trivial_mapping (GstOpusEnc * enc, guint8 mapping[256])
475 {
476   int n;
477 
478   for (n = 0; n < 255; ++n)
479     mapping[n] = n;
480 }
481 
482 static int
gst_opus_enc_find_channel_position(GstOpusEnc * enc,const GstAudioInfo * info,GstAudioChannelPosition position)483 gst_opus_enc_find_channel_position (GstOpusEnc * enc, const GstAudioInfo * info,
484     GstAudioChannelPosition position)
485 {
486   int n;
487   for (n = 0; n < enc->n_channels; ++n) {
488     if (GST_AUDIO_INFO_POSITION (info, n) == position) {
489       return n;
490     }
491   }
492   return -1;
493 }
494 
495 static int
gst_opus_enc_find_channel_position_in_vorbis_order(GstOpusEnc * enc,GstAudioChannelPosition position)496 gst_opus_enc_find_channel_position_in_vorbis_order (GstOpusEnc * enc,
497     GstAudioChannelPosition position)
498 {
499   int c;
500 
501   for (c = 0; c < enc->n_channels; ++c) {
502     if (gst_opus_channel_positions[enc->n_channels - 1][c] == position) {
503       GST_INFO_OBJECT (enc,
504           "Channel position %s maps to index %d in Vorbis order",
505           gst_opus_channel_names[position], c);
506       return c;
507     }
508   }
509   GST_WARNING_OBJECT (enc,
510       "Channel position %s is not representable in Vorbis order",
511       gst_opus_channel_names[position]);
512   return -1;
513 }
514 
515 static void
gst_opus_enc_setup_channel_mappings(GstOpusEnc * enc,const GstAudioInfo * info)516 gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
517     const GstAudioInfo * info)
518 {
519 #define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos)
520 
521   int n;
522 
523   GST_DEBUG_OBJECT (enc, "Setting up channel mapping for %d channels",
524       enc->n_channels);
525 
526   /* Start by setting up a default trivial mapping */
527   enc->n_stereo_streams = 0;
528   gst_opus_enc_setup_trivial_mapping (enc, enc->encoding_channel_mapping);
529   gst_opus_enc_setup_trivial_mapping (enc, enc->decoding_channel_mapping);
530 
531   /* For one channel, use the basic RTP mapping */
532   if (enc->n_channels == 1 && !enc->unpositioned) {
533     GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping");
534     enc->channel_mapping_family = 0;
535     /* implicit mapping for family 0 */
536     return;
537   }
538 
539   /* For two channels, use the basic RTP mapping if the channels are
540      mapped as left/right. */
541   if (enc->n_channels == 2 && !enc->unpositioned) {
542     GST_INFO_OBJECT (enc, "Stereo, trivial RTP mapping");
543     enc->channel_mapping_family = 0;
544     enc->n_stereo_streams = 1;
545     /* implicit mapping for family 0 */
546     return;
547   }
548 
549   /* For channels between 3 and 8, we use the Vorbis mapping if we can
550      find a permutation that matches it. Mono and stereo will have been taken
551      care of earlier, but this code also handles it. There are two mappings.
552      One maps the input channels to an ordering which has the natural pairs
553      first so they can benefit from the Opus stereo channel coupling, and the
554      other maps this ordering to the Vorbis ordering. */
555   if (enc->n_channels >= 3 && enc->n_channels <= 8 && !enc->unpositioned) {
556     int c0, c1, c0v, c1v;
557     int mapped;
558     gboolean positions_done[256];
559     static const GstAudioChannelPosition pairs[][2] = {
560       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
561           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
562       {GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
563           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
564       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
565           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
566       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
567           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
568       {GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
569           GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
570       {GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
571           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
572     };
573     size_t pair;
574 
575     GST_DEBUG_OBJECT (enc,
576         "In range for the Vorbis mapping, building channel mapping tables");
577 
578     enc->n_stereo_streams = 0;
579     mapped = 0;
580     for (n = 0; n < 256; ++n)
581       positions_done[n] = FALSE;
582 
583     /* First, find any natural pairs, and move them to the front */
584     for (pair = 0; pair < G_N_ELEMENTS (pairs); ++pair) {
585       GstAudioChannelPosition p0 = pairs[pair][0];
586       GstAudioChannelPosition p1 = pairs[pair][1];
587       c0 = gst_opus_enc_find_channel_position (enc, info, p0);
588       c1 = gst_opus_enc_find_channel_position (enc, info, p1);
589       if (c0 >= 0 && c1 >= 0) {
590         /* We found a natural pair */
591         GST_DEBUG_OBJECT (enc, "Natural pair '%s/%s' found at %d %d",
592             gst_opus_channel_names[p0], gst_opus_channel_names[p1], c0, c1);
593         /* Find where they map in Vorbis order */
594         c0v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p0);
595         c1v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p1);
596         if (c0v < 0 || c1v < 0) {
597           GST_WARNING_OBJECT (enc,
598               "Cannot map channel positions to Vorbis order, using unknown mapping");
599           enc->channel_mapping_family = 255;
600           enc->n_stereo_streams = 0;
601           return;
602         }
603 
604         enc->encoding_channel_mapping[mapped] = c0;
605         enc->encoding_channel_mapping[mapped + 1] = c1;
606         enc->decoding_channel_mapping[c0v] = mapped;
607         enc->decoding_channel_mapping[c1v] = mapped + 1;
608         enc->n_stereo_streams++;
609         mapped += 2;
610         positions_done[p0] = positions_done[p1] = TRUE;
611       }
612     }
613 
614     /* Now add all other input channels as mono streams */
615     for (n = 0; n < enc->n_channels; ++n) {
616       GstAudioChannelPosition position = GST_AUDIO_INFO_POSITION (info, n);
617 
618       /* if we already mapped it while searching for pairs, nothing else
619          needs to be done */
620       if (!positions_done[position]) {
621         int cv;
622         GST_DEBUG_OBJECT (enc, "Channel position %s is not mapped yet, adding",
623             gst_opus_channel_names[position]);
624         cv = gst_opus_enc_find_channel_position_in_vorbis_order (enc, position);
625         if (cv < 0)
626           g_assert_not_reached ();
627         enc->encoding_channel_mapping[mapped] = n;
628         enc->decoding_channel_mapping[cv] = mapped;
629         mapped++;
630       }
631     }
632 
633 #ifndef GST_DISABLE_GST_DEBUG
634     GST_INFO_OBJECT (enc,
635         "Mapping tables built: %d channels, %d stereo streams", enc->n_channels,
636         enc->n_stereo_streams);
637     gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
638         "Encoding mapping table", enc->n_channels,
639         enc->encoding_channel_mapping);
640     gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
641         "Decoding mapping table", enc->n_channels,
642         enc->decoding_channel_mapping);
643 #endif
644 
645     enc->channel_mapping_family = 1;
646     return;
647   }
648 
649   /* More than 8 channels, if future mappings are added for those */
650 
651   /* For other cases, we use undefined, with the default trivial mapping
652      and all mono streams */
653   if (!enc->unpositioned)
654     GST_WARNING_OBJECT (enc, "Unknown mapping");
655   else
656     GST_INFO_OBJECT (enc, "Unpositioned mapping, all channels mono");
657 
658   enc->channel_mapping_family = 255;
659   enc->n_stereo_streams = 0;
660 
661 #undef MAPS
662 }
663 
664 static gboolean
gst_opus_enc_set_format(GstAudioEncoder * benc,GstAudioInfo * info)665 gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
666 {
667   GstOpusEnc *enc;
668 
669   enc = GST_OPUS_ENC (benc);
670 
671   g_mutex_lock (&enc->property_lock);
672 
673   enc->n_channels = GST_AUDIO_INFO_CHANNELS (info);
674   enc->unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (info);
675   enc->sample_rate = GST_AUDIO_INFO_RATE (info);
676   gst_opus_enc_setup_channel_mappings (enc, info);
677   GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels,
678       enc->sample_rate);
679 
680   /* handle reconfigure */
681   if (enc->state) {
682     opus_multistream_encoder_destroy (enc->state);
683     enc->state = NULL;
684   }
685   if (!gst_opus_enc_setup (enc)) {
686     g_mutex_unlock (&enc->property_lock);
687     return FALSE;
688   }
689 
690   /* update the tags */
691   gst_opus_enc_set_tags (enc);
692 
693   enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
694 
695   /* feedback to base class */
696   gst_opus_enc_setup_base_class (enc, benc);
697 
698   g_mutex_unlock (&enc->property_lock);
699 
700   return TRUE;
701 }
702 
703 static gboolean
gst_opus_enc_setup(GstOpusEnc * enc)704 gst_opus_enc_setup (GstOpusEnc * enc)
705 {
706   int error = OPUS_OK;
707   GstCaps *caps;
708   gboolean ret;
709   gint32 lookahead;
710   const GstTagList *tags;
711   GstTagList *empty_tags = NULL;
712   GstBuffer *header, *comments;
713 
714 #ifndef GST_DISABLE_GST_DEBUG
715   GST_DEBUG_OBJECT (enc,
716       "setup: %d Hz, %d channels, %d stereo streams, family %d",
717       enc->sample_rate, enc->n_channels, enc->n_stereo_streams,
718       enc->channel_mapping_family);
719   GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams",
720       enc->n_channels, enc->n_stereo_streams);
721   gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
722       "Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping);
723   gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
724       "Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping);
725 #endif
726 
727   enc->state = opus_multistream_encoder_create (enc->sample_rate,
728       enc->n_channels, enc->n_channels - enc->n_stereo_streams,
729       enc->n_stereo_streams, enc->encoding_channel_mapping,
730       enc->audio_type, &error);
731   if (!enc->state || error != OPUS_OK)
732     goto encoder_creation_failed;
733 
734   opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0);
735   opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth),
736       0);
737   opus_multistream_encoder_ctl (enc->state,
738       OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR), 0);
739   opus_multistream_encoder_ctl (enc->state,
740       OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
741           BITRATE_TYPE_CONSTRAINED_VBR), 0);
742   opus_multistream_encoder_ctl (enc->state,
743       OPUS_SET_COMPLEXITY (enc->complexity), 0);
744   opus_multistream_encoder_ctl (enc->state,
745       OPUS_SET_INBAND_FEC (enc->inband_fec), 0);
746   opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0);
747   opus_multistream_encoder_ctl (enc->state,
748       OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0);
749 
750   opus_multistream_encoder_ctl (enc->state, OPUS_GET_LOOKAHEAD (&lookahead), 0);
751 
752   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
753       lookahead);
754 
755   /* lookahead is samples, the Opus header wants it in 48kHz samples */
756   lookahead = lookahead * 48000 / enc->sample_rate;
757   enc->lookahead = enc->pending_lookahead = lookahead;
758 
759   header = gst_codec_utils_opus_create_header (enc->sample_rate,
760       enc->n_channels, enc->channel_mapping_family,
761       enc->n_channels - enc->n_stereo_streams, enc->n_stereo_streams,
762       enc->decoding_channel_mapping, lookahead, 0);
763   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
764   if (!tags)
765     tags = empty_tags = gst_tag_list_new_empty ();
766   comments =
767       gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
768       8, "Encoded with GStreamer opusenc");
769   caps = gst_codec_utils_opus_create_caps_from_header (header, comments);
770   if (empty_tags)
771     gst_tag_list_unref (empty_tags);
772   gst_buffer_unref (header);
773   gst_buffer_unref (comments);
774 
775   /* negotiate with these caps */
776   GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
777 
778   ret = gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
779   gst_caps_unref (caps);
780 
781   return ret;
782 
783 encoder_creation_failed:
784   GST_ERROR_OBJECT (enc, "Encoder creation failed");
785   return FALSE;
786 }
787 
788 static gboolean
gst_opus_enc_sink_event(GstAudioEncoder * benc,GstEvent * event)789 gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
790 {
791   GstOpusEnc *enc;
792 
793   enc = GST_OPUS_ENC (benc);
794 
795   GST_DEBUG_OBJECT (enc, "sink event: %s", GST_EVENT_TYPE_NAME (event));
796   switch (GST_EVENT_TYPE (event)) {
797     case GST_EVENT_TAG:
798     {
799       GstTagList *list;
800       GstTagSetter *setter = GST_TAG_SETTER (enc);
801       const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
802 
803       gst_event_parse_tag (event, &list);
804       gst_tag_setter_merge_tags (setter, list, mode);
805       break;
806     }
807     case GST_EVENT_SEGMENT:
808       enc->encoded_samples = 0;
809       enc->consumed_samples = 0;
810       break;
811 
812     default:
813       break;
814   }
815 
816   return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
817 }
818 
819 static GstCaps *
gst_opus_enc_get_sink_template_caps(void)820 gst_opus_enc_get_sink_template_caps (void)
821 {
822   static gsize init = 0;
823   static GstCaps *caps = NULL;
824 
825   if (g_once_init_enter (&init)) {
826     GValue rate_array = G_VALUE_INIT;
827     GValue v = G_VALUE_INIT;
828     GstStructure *s1, *s2, *s;
829     gint i, c;
830 
831     caps = gst_caps_new_empty ();
832 
833     /* The caps is cached */
834     GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
835 
836     /* Generate our two template structures */
837     g_value_init (&rate_array, GST_TYPE_LIST);
838     g_value_init (&v, G_TYPE_INT);
839     g_value_set_int (&v, 8000);
840     gst_value_list_append_value (&rate_array, &v);
841     g_value_set_int (&v, 12000);
842     gst_value_list_append_value (&rate_array, &v);
843     g_value_set_int (&v, 16000);
844     gst_value_list_append_value (&rate_array, &v);
845     g_value_set_int (&v, 24000);
846     gst_value_list_append_value (&rate_array, &v);
847 
848     s1 = gst_structure_new ("audio/x-raw",
849         "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
850         "layout", G_TYPE_STRING, "interleaved",
851         "rate", G_TYPE_INT, 48000, NULL);
852     s2 = gst_structure_new ("audio/x-raw",
853         "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
854         "layout", G_TYPE_STRING, "interleaved", NULL);
855     gst_structure_set_value (s2, "rate", &rate_array);
856     g_value_unset (&rate_array);
857     g_value_unset (&v);
858 
859     /* Mono */
860     s = gst_structure_copy (s1);
861     gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
862     gst_caps_append_structure (caps, s);
863 
864     s = gst_structure_copy (s2);
865     gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
866     gst_caps_append_structure (caps, s);
867 
868     /* Stereo and further */
869     for (i = 2; i <= 8; i++) {
870       guint64 channel_mask = 0;
871       const GstAudioChannelPosition *pos = gst_opus_channel_positions[i - 1];
872 
873       for (c = 0; c < i; c++) {
874         channel_mask |= G_GUINT64_CONSTANT (1) << pos[c];
875       }
876 
877       s = gst_structure_copy (s1);
878       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
879           GST_TYPE_BITMASK, channel_mask, NULL);
880       gst_caps_append_structure (caps, s);
881 
882       s = gst_structure_copy (s2);
883       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
884           GST_TYPE_BITMASK, channel_mask, NULL);
885       gst_caps_append_structure (caps, s);
886 
887       /* We also allow unpositioned channels, input will be
888        * treated as a set of individual mono channels */
889       s = gst_structure_copy (s2);
890       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
891           GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
892       gst_caps_append_structure (caps, s);
893 
894       s = gst_structure_copy (s1);
895       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
896           GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
897       gst_caps_append_structure (caps, s);
898     }
899 
900     gst_structure_free (s1);
901     gst_structure_free (s2);
902 
903     g_once_init_leave (&init, 1);
904   }
905 
906   return caps;
907 }
908 
909 static GstCaps *
gst_opus_enc_sink_getcaps(GstAudioEncoder * benc,GstCaps * filter)910 gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter)
911 {
912   GstOpusEnc *enc;
913   GstCaps *caps;
914 
915   enc = GST_OPUS_ENC (benc);
916 
917   GST_DEBUG_OBJECT (enc, "sink getcaps");
918 
919   caps = gst_opus_enc_get_sink_template_caps ();
920   caps = gst_audio_encoder_proxy_getcaps (benc, caps, filter);
921 
922   GST_DEBUG_OBJECT (enc, "Returning caps: %" GST_PTR_FORMAT, caps);
923 
924   return caps;
925 }
926 
927 static GstFlowReturn
gst_opus_enc_encode(GstOpusEnc * enc,GstBuffer * buf)928 gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
929 {
930   guint8 *bdata = NULL, *data, *mdata = NULL;
931   gsize bsize, size;
932   gsize bytes;
933   gint ret = GST_FLOW_OK;
934   GstMapInfo map;
935   GstMapInfo omap;
936   gint outsize;
937   GstBuffer *outbuf;
938   guint64 trim_start = 0, trim_end = 0;
939 
940   guint max_payload_size;
941   gint frame_samples, input_samples, output_samples;
942 
943   g_mutex_lock (&enc->property_lock);
944 
945   bytes = enc->frame_samples * enc->n_channels * 2;
946   max_payload_size = enc->max_payload_size;
947   frame_samples = input_samples = enc->frame_samples;
948 
949   g_mutex_unlock (&enc->property_lock);
950 
951   if (G_LIKELY (buf)) {
952     gst_buffer_map (buf, &map, GST_MAP_READ);
953     bdata = map.data;
954     bsize = map.size;
955 
956     if (G_UNLIKELY (bsize % bytes)) {
957       gint64 diff;
958 
959       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
960       g_assert (bsize < bytes);
961 
962       input_samples = bsize / (enc->n_channels * 2);
963       diff =
964           (enc->encoded_samples + frame_samples) - (enc->consumed_samples +
965           input_samples);
966       if (diff >= 0) {
967         GST_DEBUG_OBJECT (enc,
968             "%" G_GINT64_FORMAT " extra samples of padding in this frame",
969             diff);
970         output_samples = frame_samples - diff;
971         trim_end = diff * 48000 / enc->sample_rate;
972       } else {
973         GST_DEBUG_OBJECT (enc,
974             "Need to add %" G_GINT64_FORMAT " extra samples in the next frame",
975             -diff);
976         output_samples = frame_samples;
977       }
978 
979       size = ((bsize / bytes) + 1) * bytes;
980       mdata = g_malloc0 (size);
981       /* FIXME: Instead of silence, use LPC with the last real samples.
982        * Otherwise we will create a discontinuity here, which will distort the
983        * last few encoded samples
984        */
985       memcpy (mdata, bdata, bsize);
986       data = mdata;
987     } else {
988       data = bdata;
989       size = bsize;
990 
991       /* Adjust for lookahead here */
992       if (enc->pending_lookahead) {
993         guint scaled_lookahead =
994             enc->pending_lookahead * enc->sample_rate / 48000;
995 
996         if (input_samples > scaled_lookahead) {
997           output_samples = input_samples - scaled_lookahead;
998           trim_start = enc->pending_lookahead;
999           enc->pending_lookahead = 0;
1000         } else {
1001           trim_start = ((guint64) input_samples) * 48000 / enc->sample_rate;
1002           enc->pending_lookahead -= trim_start;
1003           output_samples = 0;
1004         }
1005       } else {
1006         output_samples = input_samples;
1007       }
1008     }
1009   } else {
1010     if (enc->encoded_samples < enc->consumed_samples) {
1011       /* FIXME: Instead of silence, use LPC with the last real samples.
1012        * Otherwise we will create a discontinuity here, which will distort the
1013        * last few encoded samples
1014        */
1015       data = mdata = g_malloc0 (bytes);
1016       size = bytes;
1017       output_samples = enc->consumed_samples - enc->encoded_samples;
1018       input_samples = 0;
1019       GST_DEBUG_OBJECT (enc, "draining %d samples", output_samples);
1020       trim_end =
1021           ((guint64) frame_samples - output_samples) * 48000 / enc->sample_rate;
1022     } else if (enc->encoded_samples == enc->consumed_samples) {
1023       GST_DEBUG_OBJECT (enc, "nothing to drain");
1024       goto done;
1025     } else {
1026       g_assert_not_reached ();
1027       goto done;
1028     }
1029   }
1030 
1031   g_assert (size == bytes);
1032 
1033   outbuf =
1034       gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (enc),
1035       max_payload_size * enc->n_channels);
1036   if (!outbuf)
1037     goto done;
1038 
1039   GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
1040       frame_samples, (int) bytes);
1041 
1042   if (trim_start || trim_end) {
1043     GST_DEBUG_OBJECT (enc,
1044         "Adding trim-start %" G_GUINT64_FORMAT " trim-end %" G_GUINT64_FORMAT,
1045         trim_start, trim_end);
1046     gst_buffer_add_audio_clipping_meta (outbuf, GST_FORMAT_DEFAULT, trim_start,
1047         trim_end);
1048   }
1049 
1050   gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
1051 
1052   outsize =
1053       opus_multistream_encode (enc->state, (const gint16 *) data,
1054       frame_samples, omap.data, max_payload_size * enc->n_channels);
1055 
1056   gst_buffer_unmap (outbuf, &omap);
1057 
1058   if (outsize < 0) {
1059     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1060         ("Encoding failed (%d): %s", outsize, opus_strerror (outsize)));
1061     ret = GST_FLOW_ERROR;
1062     goto done;
1063   } else if (outsize > max_payload_size) {
1064     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1065         ("Encoded size %d is higher than max payload size (%d bytes)",
1066             outsize, max_payload_size));
1067     ret = GST_FLOW_ERROR;
1068     goto done;
1069   }
1070 
1071   GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize);
1072   gst_buffer_set_size (outbuf, outsize);
1073 
1074 
1075   ret =
1076       gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
1077       output_samples);
1078   enc->encoded_samples += output_samples;
1079   enc->consumed_samples += input_samples;
1080 
1081 done:
1082 
1083   if (bdata)
1084     gst_buffer_unmap (buf, &map);
1085 
1086   g_free (mdata);
1087 
1088   return ret;
1089 }
1090 
1091 static GstFlowReturn
gst_opus_enc_handle_frame(GstAudioEncoder * benc,GstBuffer * buf)1092 gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
1093 {
1094   GstOpusEnc *enc;
1095   GstFlowReturn ret = GST_FLOW_OK;
1096 
1097   enc = GST_OPUS_ENC (benc);
1098   GST_DEBUG_OBJECT (enc, "handle_frame");
1099   GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
1100       buf ? gst_buffer_get_size (buf) : 0);
1101 
1102   ret = gst_opus_enc_encode (enc, buf);
1103 
1104   return ret;
1105 }
1106 
1107 static void
gst_opus_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1108 gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
1109     GParamSpec * pspec)
1110 {
1111   GstOpusEnc *enc;
1112 
1113   enc = GST_OPUS_ENC (object);
1114 
1115   g_mutex_lock (&enc->property_lock);
1116 
1117   switch (prop_id) {
1118     case PROP_AUDIO_TYPE:
1119       g_value_set_enum (value, enc->audio_type);
1120       break;
1121     case PROP_BITRATE:
1122       g_value_set_int (value, enc->bitrate);
1123       break;
1124     case PROP_BANDWIDTH:
1125       g_value_set_enum (value, enc->bandwidth);
1126       break;
1127     case PROP_FRAME_SIZE:
1128       g_value_set_enum (value, enc->frame_size);
1129       break;
1130     case PROP_BITRATE_TYPE:
1131       g_value_set_enum (value, enc->bitrate_type);
1132       break;
1133     case PROP_COMPLEXITY:
1134       g_value_set_int (value, enc->complexity);
1135       break;
1136     case PROP_INBAND_FEC:
1137       g_value_set_boolean (value, enc->inband_fec);
1138       break;
1139     case PROP_DTX:
1140       g_value_set_boolean (value, enc->dtx);
1141       break;
1142     case PROP_PACKET_LOSS_PERCENT:
1143       g_value_set_int (value, enc->packet_loss_percentage);
1144       break;
1145     case PROP_MAX_PAYLOAD_SIZE:
1146       g_value_set_uint (value, enc->max_payload_size);
1147       break;
1148     default:
1149       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1150       break;
1151   }
1152 
1153   g_mutex_unlock (&enc->property_lock);
1154 }
1155 
1156 static void
gst_opus_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1157 gst_opus_enc_set_property (GObject * object, guint prop_id,
1158     const GValue * value, GParamSpec * pspec)
1159 {
1160   GstOpusEnc *enc;
1161 
1162   enc = GST_OPUS_ENC (object);
1163 
1164 #define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \
1165   g_mutex_lock (&enc->property_lock); \
1166   enc->prop = g_value_get_##type (value); \
1167   if (enc->state) { \
1168     opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \
1169   } \
1170   g_mutex_unlock (&enc->property_lock); \
1171 } while(0)
1172 
1173   switch (prop_id) {
1174     case PROP_AUDIO_TYPE:
1175       enc->audio_type = g_value_get_enum (value);
1176       break;
1177     case PROP_BITRATE:
1178       GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE);
1179       break;
1180     case PROP_BANDWIDTH:
1181       GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH);
1182       break;
1183     case PROP_FRAME_SIZE:
1184       g_mutex_lock (&enc->property_lock);
1185       enc->frame_size = g_value_get_enum (value);
1186       enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
1187       gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc));
1188       g_mutex_unlock (&enc->property_lock);
1189       break;
1190     case PROP_BITRATE_TYPE:
1191       /* this one has an opposite meaning to the opus ctl... */
1192       g_mutex_lock (&enc->property_lock);
1193       enc->bitrate_type = g_value_get_enum (value);
1194       if (enc->state) {
1195         opus_multistream_encoder_ctl (enc->state,
1196             OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR));
1197         opus_multistream_encoder_ctl (enc->state,
1198             OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
1199                 BITRATE_TYPE_CONSTRAINED_VBR), 0);
1200       }
1201       g_mutex_unlock (&enc->property_lock);
1202       break;
1203     case PROP_COMPLEXITY:
1204       GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY);
1205       break;
1206     case PROP_INBAND_FEC:
1207       GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC);
1208       break;
1209     case PROP_DTX:
1210       GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX);
1211       break;
1212     case PROP_PACKET_LOSS_PERCENT:
1213       GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC);
1214       break;
1215     case PROP_MAX_PAYLOAD_SIZE:
1216       g_mutex_lock (&enc->property_lock);
1217       enc->max_payload_size = g_value_get_uint (value);
1218       g_mutex_unlock (&enc->property_lock);
1219       break;
1220     default:
1221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1222       break;
1223   }
1224 
1225 #undef GST_OPUS_UPDATE_PROPERTY
1226 
1227 }
1228