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