2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
4 * Copyright (C) 2007-2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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.
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.
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., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:element-audioresample
25 * audioresample resamples raw audio buffers to different sample rates using
26 * a configurable windowing function to enhance quality.
29 * <title>Example launch line</title>
31 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
32 * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
33 * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
38 * - Enable SSE/ARM optimizations and select at runtime
48 #include "gstaudioresample.h"
49 #include <gst/gstutils.h>
50 #include <gst/audio/audio.h>
51 #include <gst/base/gstbasetransform.h>
55 #include <orc-test/orctest.h>
56 #include <orc-test/orcprofile.h>
59 GST_DEBUG_CATEGORY (audio_resample_debug);
60 #define GST_CAT_DEFAULT audio_resample_debug
69 #define SUPPORTED_CAPS \
71 "audio/x-raw-float, " \
72 "rate = (int) [ 1, MAX ], " \
73 "channels = (int) [ 1, MAX ], " \
74 "endianness = (int) BYTE_ORDER, " \
75 "width = (int) { 32, 64 }; " \
77 "rate = (int) [ 1, MAX ], " \
78 "channels = (int) [ 1, MAX ], " \
79 "endianness = (int) BYTE_ORDER, " \
80 "width = (int) 32, " \
81 "depth = (int) 32, " \
82 "signed = (boolean) true; " \
84 "rate = (int) [ 1, MAX ], " \
85 "channels = (int) [ 1, MAX ], " \
86 "endianness = (int) BYTE_ORDER, " \
87 "width = (int) 24, " \
88 "depth = (int) 24, " \
89 "signed = (boolean) true; " \
91 "rate = (int) [ 1, MAX ], " \
92 "channels = (int) [ 1, MAX ], " \
93 "endianness = (int) BYTE_ORDER, " \
94 "width = (int) 16, " \
95 "depth = (int) 16, " \
96 "signed = (boolean) true; " \
98 "rate = (int) [ 1, MAX ], " \
99 "channels = (int) [ 1, MAX ], " \
100 "endianness = (int) BYTE_ORDER, " \
101 "width = (int) 8, " \
102 "depth = (int) 8, " \
103 "signed = (boolean) true" \
106 /* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
107 #if defined AUDIORESAMPLE_FORMAT_INT
108 static gboolean gst_audio_resample_use_int = TRUE;
109 #elif defined AUDIORESAMPLE_FORMAT_FLOAT
110 static gboolean gst_audio_resample_use_int = FALSE;
112 static gboolean gst_audio_resample_use_int = FALSE;
115 static GstStaticPadTemplate gst_audio_resample_sink_template =
116 GST_STATIC_PAD_TEMPLATE ("sink",
117 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
119 static GstStaticPadTemplate gst_audio_resample_src_template =
120 GST_STATIC_PAD_TEMPLATE ("src",
121 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
123 static void gst_audio_resample_set_property (GObject * object,
124 guint prop_id, const GValue * value, GParamSpec * pspec);
125 static void gst_audio_resample_get_property (GObject * object,
126 guint prop_id, GValue * value, GParamSpec * pspec);
129 static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
130 GstCaps * caps, guint * size);
131 static GstCaps *gst_audio_resample_transform_caps (GstBaseTransform * base,
132 GstPadDirection direction, GstCaps * caps);
133 static void gst_audio_resample_fixate_caps (GstBaseTransform * base,
134 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
135 static gboolean gst_audio_resample_transform_size (GstBaseTransform * trans,
136 GstPadDirection direction, GstCaps * incaps, guint insize,
137 GstCaps * outcaps, guint * outsize);
138 static gboolean gst_audio_resample_set_caps (GstBaseTransform * base,
139 GstCaps * incaps, GstCaps * outcaps);
140 static GstFlowReturn gst_audio_resample_transform (GstBaseTransform * base,
141 GstBuffer * inbuf, GstBuffer * outbuf);
142 static gboolean gst_audio_resample_event (GstBaseTransform * base,
144 static gboolean gst_audio_resample_start (GstBaseTransform * base);
145 static gboolean gst_audio_resample_stop (GstBaseTransform * base);
146 static gboolean gst_audio_resample_query (GstPad * pad, GstQuery * query);
147 static const GstQueryType *gst_audio_resample_query_type (GstPad * pad);
149 GST_BOILERPLATE (GstAudioResample, gst_audio_resample, GstBaseTransform,
150 GST_TYPE_BASE_TRANSFORM);
153 gst_audio_resample_base_init (gpointer g_class)
155 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
157 gst_element_class_add_pad_template (gstelement_class,
158 gst_static_pad_template_get (&gst_audio_resample_src_template));
159 gst_element_class_add_pad_template (gstelement_class,
160 gst_static_pad_template_get (&gst_audio_resample_sink_template));
162 gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
163 "Filter/Converter/Audio", "Resamples audio",
164 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
168 gst_audio_resample_class_init (GstAudioResampleClass * klass)
170 GObjectClass *gobject_class = (GObjectClass *) klass;
172 gobject_class->set_property = gst_audio_resample_set_property;
173 gobject_class->get_property = gst_audio_resample_get_property;
175 g_object_class_install_property (gobject_class, PROP_QUALITY,
176 g_param_spec_int ("quality", "Quality", "Resample quality with 0 being "
177 "the lowest and 10 being the best",
178 SPEEX_RESAMPLER_QUALITY_MIN, SPEEX_RESAMPLER_QUALITY_MAX,
179 SPEEX_RESAMPLER_QUALITY_DEFAULT,
180 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
182 /* FIXME 0.11: Remove this property, it's just for compatibility
183 * with old audioresample
186 * GstAudioResample:filter-length:
188 * Length of the resample filter
190 * Deprectated: Use #GstAudioResample:quality property instead
192 g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH,
193 g_param_spec_int ("filter-length", "Filter length",
194 "Length of the resample filter", 0, G_MAXINT, 64,
195 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197 GST_BASE_TRANSFORM_CLASS (klass)->start =
198 GST_DEBUG_FUNCPTR (gst_audio_resample_start);
199 GST_BASE_TRANSFORM_CLASS (klass)->stop =
200 GST_DEBUG_FUNCPTR (gst_audio_resample_stop);
201 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
202 GST_DEBUG_FUNCPTR (gst_audio_resample_transform_size);
203 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
204 GST_DEBUG_FUNCPTR (gst_audio_resample_get_unit_size);
205 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
206 GST_DEBUG_FUNCPTR (gst_audio_resample_transform_caps);
207 GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
208 GST_DEBUG_FUNCPTR (gst_audio_resample_fixate_caps);
209 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
210 GST_DEBUG_FUNCPTR (gst_audio_resample_set_caps);
211 GST_BASE_TRANSFORM_CLASS (klass)->transform =
212 GST_DEBUG_FUNCPTR (gst_audio_resample_transform);
213 GST_BASE_TRANSFORM_CLASS (klass)->event =
214 GST_DEBUG_FUNCPTR (gst_audio_resample_event);
216 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
220 gst_audio_resample_init (GstAudioResample * resample,
221 GstAudioResampleClass * klass)
223 GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
225 resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
227 gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
228 gst_pad_set_query_type_function (trans->srcpad,
229 gst_audio_resample_query_type);
234 gst_audio_resample_start (GstBaseTransform * base)
236 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
238 resample->need_discont = TRUE;
240 resample->t0 = GST_CLOCK_TIME_NONE;
241 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
242 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
243 resample->samples_in = 0;
244 resample->samples_out = 0;
246 resample->tmp_in = NULL;
247 resample->tmp_in_size = 0;
248 resample->tmp_out = NULL;
249 resample->tmp_out_size = 0;
255 gst_audio_resample_stop (GstBaseTransform * base)
257 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
259 if (resample->state) {
260 resample->funcs->destroy (resample->state);
261 resample->state = NULL;
264 resample->funcs = NULL;
266 g_free (resample->tmp_in);
267 resample->tmp_in = NULL;
268 resample->tmp_in_size = 0;
270 g_free (resample->tmp_out);
271 resample->tmp_out = NULL;
272 resample->tmp_out_size = 0;
274 gst_caps_replace (&resample->sinkcaps, NULL);
275 gst_caps_replace (&resample->srccaps, NULL);
281 gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
284 gint width, channels;
285 GstStructure *structure;
288 g_return_val_if_fail (size != NULL, FALSE);
290 /* this works for both float and int */
291 structure = gst_caps_get_structure (caps, 0);
292 ret = gst_structure_get_int (structure, "width", &width);
293 ret &= gst_structure_get_int (structure, "channels", &channels);
295 if (G_UNLIKELY (!ret))
298 *size = (width / 8) * channels;
304 gst_audio_resample_transform_caps (GstBaseTransform * base,
305 GstPadDirection direction, GstCaps * caps)
311 /* transform single caps into input_caps + input_caps with the rate
312 * field set to our supported range. This ensures that upstream knows
313 * about downstream's prefered rate(s) and can negotiate accordingly. */
314 res = gst_caps_copy (caps);
316 /* first, however, check if the caps contain a range for the rate field, in
317 * which case that side isn't going to care much about the exact sample rate
318 * chosen and we should just assume things will get fixated to something sane
319 * and we may just as well offer our full range instead of the range in the
320 * caps. If the rate is not an int range value, it's likely to express a
321 * real preference or limitation and we should maintain that structure as
322 * preference by putting it first into the transformed caps, and only add
323 * our full rate range as second option */
324 s = gst_caps_get_structure (res, 0);
325 val = gst_structure_get_value (s, "rate");
326 if (val == NULL || GST_VALUE_HOLDS_INT_RANGE (val)) {
327 /* overwrite existing range, or add field if it doesn't exist yet */
328 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
330 /* append caps with full range to existing caps with non-range rate field */
331 s = gst_structure_copy (s);
332 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
333 gst_caps_append_structure (res, s);
339 /* Fixate rate to the allowed rate that has the smallest difference */
341 gst_audio_resample_fixate_caps (GstBaseTransform * base,
342 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
347 s = gst_caps_get_structure (caps, 0);
348 if (G_UNLIKELY (!gst_structure_get_int (s, "rate", &rate)))
351 s = gst_caps_get_structure (othercaps, 0);
352 gst_structure_fixate_field_nearest_int (s, "rate", rate);
355 static const SpeexResampleFuncs *
356 gst_audio_resample_get_funcs (gint width, gboolean fp)
358 const SpeexResampleFuncs *funcs = NULL;
360 if (gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
362 else if ((!gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
363 || (width == 32 && fp))
364 funcs = &float_funcs;
365 else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp))
366 funcs = &double_funcs;
368 g_assert_not_reached ();
373 static SpeexResamplerState *
374 gst_audio_resample_init_state (GstAudioResample * resample, gint width,
375 gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
377 SpeexResamplerState *ret = NULL;
378 gint err = RESAMPLER_ERR_SUCCESS;
379 const SpeexResampleFuncs *funcs = gst_audio_resample_get_funcs (width, fp);
381 ret = funcs->init (channels, inrate, outrate, quality, &err);
383 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
384 GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s",
385 funcs->strerror (err));
389 funcs->skip_zeros (ret);
395 gst_audio_resample_update_state (GstAudioResample * resample, gint width,
396 gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
399 gboolean updated_latency = FALSE;
401 updated_latency = (resample->inrate != inrate
402 || quality != resample->quality) && resample->state != NULL;
404 if (resample->state == NULL) {
406 } else if (resample->channels != channels || fp != resample->fp
407 || width != resample->width) {
408 resample->funcs->destroy (resample->state);
410 gst_audio_resample_init_state (resample, width, channels, inrate,
411 outrate, quality, fp);
413 resample->funcs = gst_audio_resample_get_funcs (width, fp);
414 ret = (resample->state != NULL);
415 } else if (resample->inrate != inrate || resample->outrate != outrate) {
416 gint err = RESAMPLER_ERR_SUCCESS;
418 err = resample->funcs->set_rate (resample->state, inrate, outrate);
420 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
421 GST_ERROR_OBJECT (resample, "Failed to update rate: %s",
422 resample->funcs->strerror (err));
424 ret = (err == RESAMPLER_ERR_SUCCESS);
425 } else if (quality != resample->quality) {
426 gint err = RESAMPLER_ERR_SUCCESS;
428 err = resample->funcs->set_quality (resample->state, quality);
430 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
431 GST_ERROR_OBJECT (resample, "Failed to update quality: %s",
432 resample->funcs->strerror (err));
434 ret = (err == RESAMPLER_ERR_SUCCESS);
437 resample->width = width;
438 resample->channels = channels;
440 resample->quality = quality;
441 resample->inrate = inrate;
442 resample->outrate = outrate;
445 gst_element_post_message (GST_ELEMENT (resample),
446 gst_message_new_latency (GST_OBJECT (resample)));
452 gst_audio_resample_reset_state (GstAudioResample * resample)
455 resample->funcs->reset_mem (resample->state);
459 gst_audio_resample_parse_caps (GstCaps * incaps,
460 GstCaps * outcaps, gint * width, gint * channels, gint * inrate,
461 gint * outrate, gboolean * fp)
463 GstStructure *structure;
465 gint mywidth, myinrate, myoutrate, mychannels;
468 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
469 GST_PTR_FORMAT, incaps, outcaps);
471 structure = gst_caps_get_structure (incaps, 0);
473 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float"))
478 ret = gst_structure_get_int (structure, "rate", &myinrate);
479 ret &= gst_structure_get_int (structure, "channels", &mychannels);
480 ret &= gst_structure_get_int (structure, "width", &mywidth);
481 if (G_UNLIKELY (!ret))
482 goto no_in_rate_channels;
484 structure = gst_caps_get_structure (outcaps, 0);
485 ret = gst_structure_get_int (structure, "rate", &myoutrate);
486 if (G_UNLIKELY (!ret))
490 *channels = mychannels;
494 *outrate = myoutrate;
505 GST_DEBUG ("could not get input rate and channels");
510 GST_DEBUG ("could not get output rate");
516 _gcd (gint a, gint b)
529 gst_audio_resample_transform_size (GstBaseTransform * base,
530 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
534 guint32 ratio_den, ratio_num;
535 gint inrate, outrate, gcd;
536 gint bytes_per_samp, channels;
538 GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
539 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
541 /* Get sample width -> bytes_per_samp, channels, inrate, outrate */
543 gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp,
544 &channels, &inrate, &outrate, NULL);
545 if (G_UNLIKELY (!ret)) {
546 GST_ERROR_OBJECT (base, "Wrong caps");
549 /* Number of samples in either buffer is size / (width*channels) ->
550 * calculate the factor */
551 bytes_per_samp = bytes_per_samp * channels / 8;
552 /* Convert source buffer size to samples */
553 size /= bytes_per_samp;
555 /* Simplify the conversion ratio factors */
556 gcd = _gcd (inrate, outrate);
557 ratio_num = inrate / gcd;
558 ratio_den = outrate / gcd;
560 if (direction == GST_PAD_SINK) {
561 /* asked to convert size of an incoming buffer. Round up the output size */
562 *othersize = gst_util_uint64_scale_int_ceil (size, ratio_den, ratio_num);
563 *othersize *= bytes_per_samp;
565 /* asked to convert size of an outgoing buffer. Round down the input size */
566 *othersize = gst_util_uint64_scale_int (size, ratio_num, ratio_den);
567 *othersize *= bytes_per_samp;
570 GST_LOG_OBJECT (base, "transformed size %d to %d", size * bytes_per_samp,
577 gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
581 gint width = 0, inrate = 0, outrate = 0, channels = 0;
583 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
585 GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
586 GST_PTR_FORMAT, incaps, outcaps);
588 ret = gst_audio_resample_parse_caps (incaps, outcaps,
589 &width, &channels, &inrate, &outrate, &fp);
591 if (G_UNLIKELY (!ret))
595 gst_audio_resample_update_state (resample, width, channels, inrate,
596 outrate, resample->quality, fp);
598 if (G_UNLIKELY (!ret))
601 /* save caps so we can short-circuit in the size_transform if the caps
603 gst_caps_replace (&resample->sinkcaps, incaps);
604 gst_caps_replace (&resample->srccaps, outcaps);
609 #define GST_MAXINT24 (8388607)
610 #define GST_MININT24 (-8388608)
612 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
613 #define GST_READ_UINT24 GST_READ_UINT24_LE
614 #define GST_WRITE_UINT24 GST_WRITE_UINT24_LE
616 #define GST_READ_UINT24 GST_READ_UINT24_BE
617 #define GST_WRITE_UINT24 GST_WRITE_UINT24_BE
621 gst_audio_resample_convert_buffer (GstAudioResample * resample,
622 const guint8 * in, guint8 * out, guint len, gboolean inverse)
624 len *= resample->channels;
627 if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
628 gint8 *o = (gint8 *) out;
629 gint16 *i = (gint16 *) in;
633 tmp = *i + (G_MAXINT8 >> 1);
634 *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8);
639 } else if (!gst_audio_resample_use_int && resample->width == 8
641 gint8 *o = (gint8 *) out;
642 gfloat *i = (gfloat *) in;
647 *o = (gint8) CLAMP (tmp * G_MAXINT8 + 0.5, G_MININT8, G_MAXINT8);
652 } else if (!gst_audio_resample_use_int && resample->width == 16
654 gint16 *o = (gint16 *) out;
655 gfloat *i = (gfloat *) in;
660 *o = (gint16) CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
665 } else if (resample->width == 24 && !resample->fp) {
666 guint8 *o = (guint8 *) out;
667 gdouble *i = (gdouble *) in;
672 GST_WRITE_UINT24 (o, (gint32) CLAMP (tmp * GST_MAXINT24 + 0.5,
673 GST_MININT24, GST_MAXINT24));
678 } else if (resample->width == 32 && !resample->fp) {
679 gint32 *o = (gint32 *) out;
680 gdouble *i = (gdouble *) in;
685 *o = (gint32) CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32);
691 g_assert_not_reached ();
694 if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
695 gint8 *i = (gint8 *) in;
696 gint16 *o = (gint16 *) out;
706 } else if (!gst_audio_resample_use_int && resample->width == 8
708 gint8 *i = (gint8 *) in;
709 gfloat *o = (gfloat *) out;
714 *o = tmp / G_MAXINT8;
719 } else if (!gst_audio_resample_use_int && resample->width == 16
721 gint16 *i = (gint16 *) in;
722 gfloat *o = (gfloat *) out;
727 *o = tmp / G_MAXINT16;
732 } else if (resample->width == 24 && !resample->fp) {
733 guint8 *i = (guint8 *) in;
734 gdouble *o = (gdouble *) out;
739 tmp2 = GST_READ_UINT24 (i);
740 if (tmp2 & 0x00800000)
743 *o = tmp / GST_MAXINT24;
748 } else if (resample->width == 32 && !resample->fp) {
749 gint32 *i = (gint32 *) in;
750 gdouble *o = (gdouble *) out;
755 *o = tmp / G_MAXINT32;
761 g_assert_not_reached ();
767 gst_audio_resample_workspace_realloc (guint8 ** workspace, guint * size,
771 if (new_size <= *size)
772 /* no need to resize */
774 new = g_realloc (*workspace, new_size);
776 /* failure (re)allocating memeory */
785 gst_audio_resample_push_drain (GstAudioResample * resample)
790 guint history_len, out_len, out_processed;
794 if (!resample->state)
797 /* Don't drain samples if we were reset. */
798 if (!GST_CLOCK_TIME_IS_VALID (resample->t0))
801 resample->funcs->get_ratio (resample->state, &num, &den);
803 history_len = resample->funcs->get_input_latency (resample->state);
804 out_len = out_processed =
805 gst_util_uint64_scale_int_ceil (history_len, den, num);
806 outsize = out_len * resample->channels * (resample->width / 8);
809 gst_pad_alloc_buffer_and_set_caps (GST_BASE_TRANSFORM_SRC_PAD (resample),
810 GST_BUFFER_OFFSET_NONE, outsize,
811 GST_PAD_CAPS (GST_BASE_TRANSFORM_SRC_PAD (resample)), &outbuf);
812 if (G_UNLIKELY (res != GST_FLOW_OK)) {
813 GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes",
818 if (resample->funcs->width != resample->width) {
819 /* need to convert data format; allocate workspace */
820 if (!gst_audio_resample_workspace_realloc (&resample->tmp_out,
821 &resample->tmp_out_size, (resample->funcs->width / 8) * out_len *
822 resample->channels)) {
823 GST_ERROR_OBJECT (resample, "failed to allocate workspace");
828 err = resample->funcs->process (resample->state, NULL, &history_len,
829 resample->tmp_out, &out_processed);
831 /* convert output format */
832 gst_audio_resample_convert_buffer (resample, resample->tmp_out,
833 GST_BUFFER_DATA (outbuf), out_processed, TRUE);
835 /* don't need to convert data format; process */
836 err = resample->funcs->process (resample->state, NULL, &history_len,
837 GST_BUFFER_DATA (outbuf), &out_processed);
840 /* If we wrote more than allocated something is really wrong now
841 * and we should better abort immediately */
842 g_assert (out_len >= out_processed);
844 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
845 GST_WARNING_OBJECT (resample, "Failed to process drain: %s",
846 resample->funcs->strerror (err));
847 gst_buffer_unref (outbuf);
851 if (G_UNLIKELY (out_processed == 0)) {
852 GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
853 gst_buffer_unref (outbuf);
858 if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
859 GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
860 gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
862 GST_BUFFER_DURATION (outbuf) =
863 gst_util_uint64_scale_int_round (resample->samples_out + out_processed,
864 GST_SECOND, resample->outrate) - GST_BUFFER_TIMESTAMP (outbuf);
866 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
867 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
870 if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
871 GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
872 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed;
874 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
875 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
878 resample->samples_out += out_processed;
879 resample->samples_in += 0;
881 GST_BUFFER_SIZE (outbuf) =
882 out_processed * resample->channels * (resample->width / 8);
884 GST_LOG_OBJECT (resample,
885 "Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
886 " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %"
887 G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
888 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
889 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
890 GST_BUFFER_OFFSET_END (outbuf));
892 res = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (resample), outbuf);
894 if (G_UNLIKELY (res != GST_FLOW_OK))
895 GST_WARNING_OBJECT (resample, "Failed to push drain: %s",
896 gst_flow_get_name (res));
902 gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
904 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
906 switch (GST_EVENT_TYPE (event)) {
907 case GST_EVENT_FLUSH_STOP:
908 gst_audio_resample_reset_state (resample);
909 resample->t0 = GST_CLOCK_TIME_NONE;
910 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
911 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
912 resample->samples_in = 0;
913 resample->samples_out = 0;
914 resample->need_discont = TRUE;
916 case GST_EVENT_NEWSEGMENT:
917 gst_audio_resample_push_drain (resample);
918 gst_audio_resample_reset_state (resample);
919 resample->t0 = GST_CLOCK_TIME_NONE;
920 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
921 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
922 resample->samples_in = 0;
923 resample->samples_out = 0;
924 resample->need_discont = TRUE;
927 gst_audio_resample_push_drain (resample);
928 gst_audio_resample_reset_state (resample);
934 return parent_class->event (base, event);
938 gst_audio_resample_check_discont (GstAudioResample * resample, GstBuffer * buf)
943 /* is the incoming buffer a discontinuity? */
944 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf)))
947 /* no valid timestamps or offsets to compare --> no discontinuity */
948 if (G_UNLIKELY (!(GST_BUFFER_TIMESTAMP_IS_VALID (buf) &&
949 GST_CLOCK_TIME_IS_VALID (resample->t0))))
952 /* convert the inbound timestamp to an offset. */
954 gst_util_uint64_scale_int_round (GST_BUFFER_TIMESTAMP (buf) -
955 resample->t0, resample->inrate, GST_SECOND);
957 /* many elements generate imperfect streams due to rounding errors, so we
958 * permit a small error (up to one sample) without triggering a filter
959 * flush/restart (if triggered incorrectly, this will be audible) */
960 delta = ABS ((gint64) (offset - resample->samples_in));
964 GST_WARNING_OBJECT (resample,
965 "encountered timestamp discontinuity of %" G_GUINT64_FORMAT " samples = %"
966 GST_TIME_FORMAT, delta,
967 GST_TIME_ARGS (gst_util_uint64_scale_int_round (delta, GST_SECOND,
973 gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
976 guint32 in_len, in_processed;
977 guint32 out_len, out_processed;
980 in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
981 out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
983 in_len /= (resample->width / 8);
984 out_len /= (resample->width / 8);
986 in_processed = in_len;
987 out_processed = out_len;
989 if (resample->funcs->width != resample->width) {
990 /* need to convert data format for processing; ensure we have enough
991 * workspace available */
992 if (!gst_audio_resample_workspace_realloc (&resample->tmp_in,
993 &resample->tmp_in_size, in_len * resample->channels *
994 (resample->funcs->width / 8)) ||
995 !gst_audio_resample_workspace_realloc (&resample->tmp_out,
996 &resample->tmp_out_size, out_len * resample->channels *
997 (resample->funcs->width / 8))) {
998 GST_ERROR_OBJECT (resample, "failed to allocate workspace");
999 return GST_FLOW_ERROR;
1003 gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
1004 resample->tmp_in, in_len, FALSE);
1007 err = resample->funcs->process (resample->state,
1008 resample->tmp_in, &in_processed, resample->tmp_out, &out_processed);
1010 /* convert output */
1011 gst_audio_resample_convert_buffer (resample, resample->tmp_out,
1012 GST_BUFFER_DATA (outbuf), out_processed, TRUE);
1014 /* no format conversion required; process */
1015 err = resample->funcs->process (resample->state,
1016 GST_BUFFER_DATA (inbuf), &in_processed,
1017 GST_BUFFER_DATA (outbuf), &out_processed);
1020 /* If we wrote more than allocated something is really wrong now and we
1021 * should better abort immediately */
1022 g_assert (out_len >= out_processed);
1024 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
1025 GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
1026 resample->funcs->strerror (err));
1027 return GST_FLOW_ERROR;
1030 if (G_UNLIKELY (in_len != in_processed)) {
1031 GST_WARNING_OBJECT (resample, "converted %d of %d input samples",
1032 in_processed, in_len);
1036 if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
1037 GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
1038 gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
1040 GST_BUFFER_DURATION (outbuf) =
1041 gst_util_uint64_scale_int_round (resample->samples_out + out_processed,
1042 GST_SECOND, resample->outrate) - GST_BUFFER_TIMESTAMP (outbuf);
1044 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
1045 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1048 if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
1049 GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
1050 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed;
1052 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
1053 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
1056 resample->samples_out += out_processed;
1057 resample->samples_in += in_len;
1059 GST_BUFFER_SIZE (outbuf) =
1060 out_processed * resample->channels * (resample->width / 8);
1062 GST_LOG_OBJECT (resample,
1063 "Converted to buffer of %" G_GUINT32_FORMAT
1064 " samples (%u bytes) with timestamp %" GST_TIME_FORMAT ", duration %"
1065 GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", offset_end %"
1066 G_GUINT64_FORMAT, out_processed, GST_BUFFER_SIZE (outbuf),
1067 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1068 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1069 GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
1071 if (out_processed == 0) {
1072 GST_DEBUG_OBJECT (resample, "buffer dropped");
1073 return GST_BASE_TRANSFORM_FLOW_DROPPED;
1078 static GstFlowReturn
1079 gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
1082 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
1086 if (resample->state == NULL) {
1087 if (G_UNLIKELY (!(resample->state =
1088 gst_audio_resample_init_state (resample, resample->width,
1089 resample->channels, resample->inrate, resample->outrate,
1090 resample->quality, resample->fp))))
1091 return GST_FLOW_ERROR;
1094 gst_audio_resample_get_funcs (resample->width, resample->fp);
1097 size = GST_BUFFER_SIZE (inbuf);
1099 GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %"
1100 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
1101 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
1102 size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
1103 GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
1104 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
1106 /* check for timestamp discontinuities; flush/reset if needed, and set
1107 * flag to resync timestamp and offset counters and send event
1109 if (G_UNLIKELY (gst_audio_resample_check_discont (resample, inbuf))) {
1110 gst_audio_resample_reset_state (resample);
1111 resample->need_discont = TRUE;
1114 /* handle discontinuity */
1115 if (G_UNLIKELY (resample->need_discont)) {
1117 resample->samples_in = 0;
1118 resample->samples_out = 0;
1119 GST_DEBUG_OBJECT (resample, "found discontinuity; resyncing");
1120 /* resync the timestamp and offset counters if possible */
1121 if (GST_BUFFER_TIMESTAMP_IS_VALID (inbuf)) {
1122 resample->t0 = GST_BUFFER_TIMESTAMP (inbuf);
1124 GST_DEBUG_OBJECT (resample, "... but new timestamp is invalid");
1125 resample->t0 = GST_CLOCK_TIME_NONE;
1127 if (GST_BUFFER_OFFSET_IS_VALID (inbuf)) {
1128 resample->in_offset0 = GST_BUFFER_OFFSET (inbuf);
1129 resample->out_offset0 =
1130 gst_util_uint64_scale_int_round (resample->in_offset0,
1131 resample->outrate, resample->inrate);
1133 GST_DEBUG_OBJECT (resample, "... but new offset is invalid");
1134 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
1135 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
1137 /* set DISCONT flag on output buffer */
1138 GST_DEBUG_OBJECT (resample, "marking this buffer with the DISCONT flag");
1139 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1140 resample->need_discont = FALSE;
1143 ret = gst_audio_resample_process (resample, inbuf, outbuf);
1144 if (G_UNLIKELY (ret != GST_FLOW_OK))
1147 GST_DEBUG_OBJECT (resample, "input = samples [%" G_GUINT64_FORMAT ", %"
1148 G_GUINT64_FORMAT ") = [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT
1149 ") ns; output = samples [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT
1150 ") = [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ") ns",
1151 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
1152 GST_BUFFER_TIMESTAMP (inbuf), GST_BUFFER_TIMESTAMP (inbuf) +
1153 GST_BUFFER_DURATION (inbuf), GST_BUFFER_OFFSET (outbuf),
1154 GST_BUFFER_OFFSET_END (outbuf), GST_BUFFER_TIMESTAMP (outbuf),
1155 GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf));
1161 gst_audio_resample_query (GstPad * pad, GstQuery * query)
1163 GstAudioResample *resample = GST_AUDIO_RESAMPLE (gst_pad_get_parent (pad));
1164 GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
1165 gboolean res = TRUE;
1167 switch (GST_QUERY_TYPE (query)) {
1168 case GST_QUERY_LATENCY:
1170 GstClockTime min, max;
1174 gint rate = resample->inrate;
1175 gint resampler_latency;
1177 if (resample->state)
1179 resample->funcs->get_input_latency (resample->state);
1181 resampler_latency = 0;
1183 if (gst_base_transform_is_passthrough (trans))
1184 resampler_latency = 0;
1186 if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM_SINK_PAD (trans)))) {
1187 if ((res = gst_pad_query (peer, query))) {
1188 gst_query_parse_latency (query, &live, &min, &max);
1190 GST_DEBUG_OBJECT (resample, "Peer latency: min %"
1191 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1192 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1194 /* add our own latency */
1195 if (rate != 0 && resampler_latency != 0)
1196 latency = gst_util_uint64_scale_round (resampler_latency,
1201 GST_DEBUG_OBJECT (resample, "Our latency: %" GST_TIME_FORMAT,
1202 GST_TIME_ARGS (latency));
1205 if (GST_CLOCK_TIME_IS_VALID (max))
1208 GST_DEBUG_OBJECT (resample, "Calculated total latency : min %"
1209 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1210 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1212 gst_query_set_latency (query, live, min, max);
1214 gst_object_unref (peer);
1219 res = gst_pad_query_default (pad, query);
1222 gst_object_unref (resample);
1226 static const GstQueryType *
1227 gst_audio_resample_query_type (GstPad * pad)
1229 static const GstQueryType types[] = {
1238 gst_audio_resample_set_property (GObject * object, guint prop_id,
1239 const GValue * value, GParamSpec * pspec)
1241 GstAudioResample *resample;
1243 resample = GST_AUDIO_RESAMPLE (object);
1247 GST_BASE_TRANSFORM_LOCK (resample);
1248 resample->quality = g_value_get_int (value);
1249 GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
1251 gst_audio_resample_update_state (resample, resample->width,
1252 resample->channels, resample->inrate, resample->outrate,
1253 resample->quality, resample->fp);
1254 GST_BASE_TRANSFORM_UNLOCK (resample);
1256 case PROP_FILTER_LENGTH:{
1257 gint filter_length = g_value_get_int (value);
1259 GST_BASE_TRANSFORM_LOCK (resample);
1260 if (filter_length <= 8)
1261 resample->quality = 0;
1262 else if (filter_length <= 16)
1263 resample->quality = 1;
1264 else if (filter_length <= 32)
1265 resample->quality = 2;
1266 else if (filter_length <= 48)
1267 resample->quality = 3;
1268 else if (filter_length <= 64)
1269 resample->quality = 4;
1270 else if (filter_length <= 80)
1271 resample->quality = 5;
1272 else if (filter_length <= 96)
1273 resample->quality = 6;
1274 else if (filter_length <= 128)
1275 resample->quality = 7;
1276 else if (filter_length <= 160)
1277 resample->quality = 8;
1278 else if (filter_length <= 192)
1279 resample->quality = 9;
1281 resample->quality = 10;
1283 GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
1285 gst_audio_resample_update_state (resample, resample->width,
1286 resample->channels, resample->inrate, resample->outrate,
1287 resample->quality, resample->fp);
1288 GST_BASE_TRANSFORM_UNLOCK (resample);
1292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1298 gst_audio_resample_get_property (GObject * object, guint prop_id,
1299 GValue * value, GParamSpec * pspec)
1301 GstAudioResample *resample;
1303 resample = GST_AUDIO_RESAMPLE (object);
1307 g_value_set_int (value, resample->quality);
1309 case PROP_FILTER_LENGTH:
1310 switch (resample->quality) {
1312 g_value_set_int (value, 8);
1315 g_value_set_int (value, 16);
1318 g_value_set_int (value, 32);
1321 g_value_set_int (value, 48);
1324 g_value_set_int (value, 64);
1327 g_value_set_int (value, 80);
1330 g_value_set_int (value, 96);
1333 g_value_set_int (value, 128);
1336 g_value_set_int (value, 160);
1339 g_value_set_int (value, 192);
1342 g_value_set_int (value, 256);
1347 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1352 /* FIXME: should have a benchmark fallback for the case where orc is disabled */
1353 #if defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC)
1355 #define BENCHMARK_SIZE 512
1358 _benchmark_int_float (SpeexResamplerState * st)
1360 gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
1361 gfloat in_tmp[BENCHMARK_SIZE], out_tmp[BENCHMARK_SIZE / 2];
1363 guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
1365 for (i = 0; i < BENCHMARK_SIZE; i++) {
1367 in_tmp[i] = tmp / G_MAXINT16;
1370 resample_float_resampler_process_interleaved_float (st,
1371 (const guint8 *) in_tmp, &inlen, (guint8 *) out_tmp, &outlen);
1374 GST_ERROR ("Failed to use float resampler");
1378 for (i = 0; i < outlen; i++) {
1379 gfloat tmp = out_tmp[i];
1380 out[i] = CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
1387 _benchmark_int_int (SpeexResamplerState * st)
1389 gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
1390 guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
1392 resample_int_resampler_process_interleaved_int (st, (const guint8 *) in,
1393 &inlen, (guint8 *) out, &outlen);
1396 GST_ERROR ("Failed to use int resampler");
1404 _benchmark_integer_resampling (void)
1408 SpeexResamplerState *sta, *stb;
1411 orc_profile_init (&a);
1412 orc_profile_init (&b);
1414 sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL);
1416 GST_ERROR ("Failed to create float resampler state");
1420 stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL);
1422 resample_float_resampler_destroy (sta);
1423 GST_ERROR ("Failed to create int resampler state");
1428 for (i = 0; i < 10; i++) {
1429 orc_profile_start (&a);
1430 if (!_benchmark_int_float (sta))
1432 orc_profile_stop (&a);
1436 for (i = 0; i < 10; i++) {
1437 orc_profile_start (&b);
1438 if (!_benchmark_int_int (stb))
1440 orc_profile_stop (&b);
1443 /* Handle results */
1444 orc_profile_get_ave_std (&a, &av, NULL);
1445 orc_profile_get_ave_std (&b, &bv, NULL);
1447 /* Remember benchmark result in global variable */
1448 gst_audio_resample_use_int = (av > bv);
1449 resample_float_resampler_destroy (sta);
1450 resample_int_resampler_destroy (stb);
1453 GST_INFO ("Using integer resampler if appropiate: %lf < %lf", bv, av);
1455 GST_INFO ("Using float resampler for everything: %lf <= %lf", av, bv);
1460 resample_float_resampler_destroy (sta);
1461 resample_int_resampler_destroy (stb);
1465 #endif /* defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC) */
1468 plugin_init (GstPlugin * plugin)
1470 GST_DEBUG_CATEGORY_INIT (audio_resample_debug, "audioresample", 0,
1471 "audio resampling element");
1473 #if defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC)
1474 if (!_benchmark_integer_resampling ())
1477 GST_WARNING ("Orc disabled, can't benchmark int vs. float resampler");
1479 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
1480 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
1481 GST_CAT_WARNING (GST_CAT_PERFORMANCE, "orc disabled, no benchmarking done");
1485 if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
1486 GST_TYPE_AUDIO_RESAMPLE)) {
1493 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1496 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1497 GST_PACKAGE_ORIGIN);