mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-27 09:38:17 +00:00
sys/oss/gstosselement.c: Add code to handle rate probing (bug #120883)
Original commit message from CVS: * sys/oss/gstosselement.c: (gst_osselement_sync_parms), (gst_osselement_close_audio), (gst_osselement_probe_caps), (gst_osselement_get_format_structure), (gst_osselement_rate_probe_check), (gst_osselement_rate_add_range), (gst_osselement_rate_check_rate), (gst_osselement_rate_add_rate), (gst_osselement_rate_int_compare): Add code to handle rate probing (bug #120883) * sys/oss/gstosselement.h: same * sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_getcaps): Use rate probing provided by osselement. * sys/oss/gstosssrc.c: (gst_osssrc_init), (gst_osssrc_getcaps): same
This commit is contained in:
parent
f2ad493ba4
commit
d21f04ca6f
5 changed files with 396 additions and 4 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2004-03-24 David Schleef <ds@schleef.org>
|
||||
|
||||
* sys/oss/gstosselement.c: (gst_osselement_sync_parms),
|
||||
(gst_osselement_close_audio), (gst_osselement_probe_caps),
|
||||
(gst_osselement_get_format_structure),
|
||||
(gst_osselement_rate_probe_check), (gst_osselement_rate_add_range),
|
||||
(gst_osselement_rate_check_rate), (gst_osselement_rate_add_rate),
|
||||
(gst_osselement_rate_int_compare): Add code to handle rate probing
|
||||
(bug #120883)
|
||||
* sys/oss/gstosselement.h: same
|
||||
* sys/oss/gstosssink.c: (gst_osssink_init), (gst_osssink_getcaps):
|
||||
Use rate probing provided by osselement.
|
||||
* sys/oss/gstosssrc.c: (gst_osssrc_init), (gst_osssrc_getcaps): same
|
||||
|
||||
2004-03-24 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
|
||||
* ext/xvid/gstxvidenc.c: (gst_xvidenc_set_property),
|
||||
|
|
|
@ -642,7 +642,7 @@ gst_osselement_sync_parms (GstOssElement * oss)
|
|||
g_warning
|
||||
("couldn't set the right number of channels (wanted %d, got %d), enjoy the tone difference",
|
||||
target_channels, oss->channels);
|
||||
if (target_rate != oss->rate)
|
||||
if (target_rate < oss->rate - 1 || target_rate > oss->rate + 1)
|
||||
g_warning
|
||||
("couldn't set the right sample rate (wanted %d, got %d), enjoy the speed difference",
|
||||
target_rate, oss->rate);
|
||||
|
@ -806,6 +806,10 @@ static void
|
|||
gst_osselement_close_audio (GstOssElement * oss)
|
||||
{
|
||||
gst_ossmixer_free_list (oss);
|
||||
if (oss->probed_caps) {
|
||||
gst_caps_free (oss->probed_caps);
|
||||
oss->probed_caps = NULL;
|
||||
}
|
||||
|
||||
if (oss->fd < 0)
|
||||
return;
|
||||
|
@ -967,3 +971,336 @@ gst_osselement_change_state (GstElement * element)
|
|||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* rate probing code */
|
||||
|
||||
|
||||
#if 0
|
||||
#include <sys/soundcard.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
typedef struct _GstOssProbe GstOssProbe;
|
||||
struct _GstOssProbe
|
||||
{
|
||||
int fd;
|
||||
int format;
|
||||
int n_channels;
|
||||
GArray *rates;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
typedef struct _GstOssRange GstOssRange;
|
||||
struct _GstOssRange
|
||||
{
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
static GstStructure *gst_osselement_get_format_structure (unsigned int
|
||||
format_bit);
|
||||
static gboolean gst_osselement_rate_probe_check (GstOssProbe * probe);
|
||||
static int gst_osselement_rate_check_rate (GstOssProbe * probe, int irate);
|
||||
static void gst_osselement_rate_add_range (GQueue * queue, int min, int max);
|
||||
static void gst_osselement_rate_add_rate (GArray * array, int rate);
|
||||
static int gst_osselement_rate_int_compare (gconstpointer a, gconstpointer b);
|
||||
|
||||
void
|
||||
gst_osselement_probe_caps (GstOssElement * oss)
|
||||
{
|
||||
GstOssProbe *probe;
|
||||
int i;
|
||||
gboolean ret;
|
||||
GstStructure *structure;
|
||||
unsigned int format_bit;
|
||||
unsigned int format_mask;
|
||||
GstCaps *caps;
|
||||
|
||||
if (oss->probed_caps != NULL)
|
||||
return;
|
||||
if (oss->fd == -1)
|
||||
return;
|
||||
|
||||
/* FIXME test make sure we're not currently playing */
|
||||
/* FIXME test both mono and stereo */
|
||||
|
||||
format_mask = AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 |
|
||||
AFMT_U16_LE | AFMT_U16_BE;
|
||||
format_mask &= oss->caps;
|
||||
|
||||
caps = gst_caps_new_empty ();
|
||||
|
||||
/* assume that the most significant bit of format_mask is 0 */
|
||||
for (format_bit = 1; format_bit < format_mask; format_bit <<= 1) {
|
||||
if (format_bit & format_mask) {
|
||||
GValue rate_value = { 0 };
|
||||
|
||||
probe = g_new0 (GstOssProbe, 1);
|
||||
probe->fd = oss->fd;
|
||||
probe->format = format_bit;
|
||||
probe->n_channels = 2;
|
||||
|
||||
ret = gst_osselement_rate_probe_check (probe);
|
||||
if (probe->min == -1 || probe->max == -1) {
|
||||
g_array_free (probe->rates, TRUE);
|
||||
g_free (probe);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
GValue value = { 0 };
|
||||
|
||||
g_array_sort (probe->rates, gst_osselement_rate_int_compare);
|
||||
|
||||
g_value_init (&rate_value, GST_TYPE_LIST);
|
||||
g_value_init (&value, G_TYPE_INT);
|
||||
|
||||
for (i = 0; i < probe->rates->len; i++) {
|
||||
g_value_set_int (&value, g_array_index (probe->rates, int, i));
|
||||
|
||||
gst_value_list_append_value (&rate_value, &value);
|
||||
}
|
||||
|
||||
g_value_unset (&value);
|
||||
} else {
|
||||
/* one big range */
|
||||
g_value_init (&rate_value, GST_TYPE_INT_RANGE);
|
||||
gst_value_set_int_range (&rate_value, probe->min, probe->max);
|
||||
}
|
||||
|
||||
g_array_free (probe->rates, TRUE);
|
||||
g_free (probe);
|
||||
|
||||
structure = gst_osselement_get_format_structure (format_bit);
|
||||
gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
|
||||
gst_structure_set_value (structure, "rate", &rate_value);
|
||||
g_value_unset (&rate_value);
|
||||
|
||||
gst_caps_append_structure (caps, structure);
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps);
|
||||
oss->probed_caps = caps;
|
||||
}
|
||||
|
||||
static GstStructure *
|
||||
gst_osselement_get_format_structure (unsigned int format_bit)
|
||||
{
|
||||
GstStructure *structure;
|
||||
int endianness;
|
||||
gboolean sign;
|
||||
int width;
|
||||
|
||||
switch (format_bit) {
|
||||
case AFMT_U8:
|
||||
endianness = 0;
|
||||
sign = FALSE;
|
||||
width = 8;
|
||||
break;
|
||||
case AFMT_S16_LE:
|
||||
endianness = G_LITTLE_ENDIAN;
|
||||
sign = TRUE;
|
||||
width = 16;
|
||||
break;
|
||||
case AFMT_S16_BE:
|
||||
endianness = G_BIG_ENDIAN;
|
||||
sign = TRUE;
|
||||
width = 16;
|
||||
break;
|
||||
case AFMT_S8:
|
||||
endianness = 0;
|
||||
sign = TRUE;
|
||||
width = 8;
|
||||
break;
|
||||
case AFMT_U16_LE:
|
||||
endianness = G_LITTLE_ENDIAN;
|
||||
sign = FALSE;
|
||||
width = 16;
|
||||
break;
|
||||
case AFMT_U16_BE:
|
||||
endianness = G_BIG_ENDIAN;
|
||||
sign = FALSE;
|
||||
width = 16;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
structure = gst_structure_new ("audio/x-raw-int",
|
||||
"width", G_TYPE_INT, width,
|
||||
"depth", G_TYPE_INT, width, "signed", G_TYPE_BOOLEAN, sign, NULL);
|
||||
|
||||
if (endianness) {
|
||||
gst_structure_set (structure, "endianness", G_TYPE_INT, endianness, NULL);
|
||||
}
|
||||
|
||||
return structure;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_osselement_rate_probe_check (GstOssProbe * probe)
|
||||
{
|
||||
GstOssRange *range;
|
||||
GQueue *ranges;
|
||||
int exact_rates = 0;
|
||||
gboolean checking_exact_rates = TRUE;
|
||||
int n_checks = 0;
|
||||
gboolean result = TRUE;
|
||||
|
||||
ranges = g_queue_new ();
|
||||
|
||||
probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
|
||||
|
||||
probe->min = gst_osselement_rate_check_rate (probe, 1000);
|
||||
n_checks++;
|
||||
probe->max = gst_osselement_rate_check_rate (probe, 100000);
|
||||
n_checks++;
|
||||
if (probe->min == -1 || probe->max == -1) {
|
||||
GST_DEBUG ("unexpected check_rate error");
|
||||
return FALSE;
|
||||
}
|
||||
gst_osselement_rate_add_range (ranges, probe->min + 1, probe->max - 1);
|
||||
|
||||
while ((range = g_queue_pop_head (ranges))) {
|
||||
int min1;
|
||||
int max1;
|
||||
int mid;
|
||||
int mid_ret;
|
||||
|
||||
GST_DEBUG ("checking [%d,%d]\n", range->min, range->max);
|
||||
|
||||
mid = (range->min + range->max) / 2;
|
||||
mid_ret = gst_osselement_rate_check_rate (probe, mid);
|
||||
if (mid_ret == -1) {
|
||||
/* FIXME ioctl returned an error. do something */
|
||||
GST_DEBUG ("unexpected check_rate error");
|
||||
}
|
||||
n_checks++;
|
||||
|
||||
if (mid == mid_ret && checking_exact_rates) {
|
||||
int max_exact_matches = 20;
|
||||
|
||||
exact_rates++;
|
||||
if (exact_rates > max_exact_matches) {
|
||||
GST_DEBUG ("got %d exact rates, assuming all are exact\n",
|
||||
max_exact_matches);
|
||||
result = FALSE;
|
||||
g_free (range);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
checking_exact_rates = FALSE;
|
||||
}
|
||||
|
||||
/* Assume that the rate is arithmetically rounded to the nearest
|
||||
* supported rate. */
|
||||
if (mid == mid_ret) {
|
||||
min1 = mid - 1;
|
||||
max1 = mid + 1;
|
||||
} else {
|
||||
if (mid < mid_ret) {
|
||||
min1 = mid - (mid_ret - mid);
|
||||
max1 = mid_ret + 1;
|
||||
} else {
|
||||
min1 = mid_ret - 1;
|
||||
max1 = mid + (mid - mid_ret);
|
||||
}
|
||||
}
|
||||
|
||||
gst_osselement_rate_add_range (ranges, range->min, min1);
|
||||
gst_osselement_rate_add_range (ranges, max1, range->max);
|
||||
|
||||
g_free (range);
|
||||
}
|
||||
|
||||
while ((range = g_queue_pop_head (ranges))) {
|
||||
g_free (range);
|
||||
}
|
||||
g_queue_free (ranges);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_osselement_rate_add_range (GQueue * queue, int min, int max)
|
||||
{
|
||||
if (min <= max) {
|
||||
GstOssRange *range = g_new0 (GstOssRange, 1);
|
||||
|
||||
range->min = min;
|
||||
range->max = max;
|
||||
|
||||
g_queue_push_tail (queue, range);
|
||||
/* push_head also works, but has different probing behavior */
|
||||
/*g_queue_push_head (queue, range); */
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gst_osselement_rate_check_rate (GstOssProbe * probe, int irate)
|
||||
{
|
||||
int rate;
|
||||
int format;
|
||||
int n_channels;
|
||||
int ret;
|
||||
|
||||
rate = irate;
|
||||
format = probe->format;
|
||||
n_channels = probe->n_channels;
|
||||
|
||||
ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
GST_DEBUG ("rate %d -> %d\n", irate, rate);
|
||||
|
||||
if (rate == irate - 1 || rate == irate + 1) {
|
||||
rate = irate;
|
||||
}
|
||||
gst_osselement_rate_add_rate (probe->rates, rate);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_osselement_rate_add_rate (GArray * array, int rate)
|
||||
{
|
||||
int i;
|
||||
int val;
|
||||
|
||||
for (i = 0; i < array->len; i++) {
|
||||
val = g_array_index (array, int, i);
|
||||
|
||||
if (val == rate)
|
||||
return;
|
||||
}
|
||||
GST_DEBUG ("supported rate: %d\n", rate);
|
||||
g_array_append_val (array, rate);
|
||||
}
|
||||
|
||||
static int
|
||||
gst_osselement_rate_int_compare (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const int *va = (const int *) a;
|
||||
const int *vb = (const int *) b;
|
||||
|
||||
if (*va < *vb)
|
||||
return -1;
|
||||
if (*va > *vb)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ struct _GstOssElement
|
|||
guint64 fragment_time;
|
||||
gint fragment_size;
|
||||
GstOssOpenMode mode;
|
||||
GstCaps *probed_caps;
|
||||
|
||||
/* stats bytes per *second* */
|
||||
guint bps;
|
||||
|
@ -118,6 +119,7 @@ gboolean gst_osselement_convert (GstOssElement *oss,
|
|||
gint64 src_value,
|
||||
GstFormat *dest_format,
|
||||
gint64 *dest_value);
|
||||
void gst_osselement_probe_caps (GstOssElement *oss);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ static gboolean gst_osssink_sink_query (GstPad * pad, GstQueryType type,
|
|||
GstFormat * format, gint64 * value);
|
||||
|
||||
static GstCaps *gst_osssink_sink_fixate (GstPad * pad, const GstCaps * caps);
|
||||
static GstCaps *gst_osssink_getcaps (GstPad * pad);
|
||||
static GstPadLinkReturn gst_osssink_sinkconnect (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
|
||||
|
@ -96,7 +97,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
"signed = (boolean) { TRUE, FALSE }, "
|
||||
"width = (int) { 8, 16 }, "
|
||||
"depth = (int) { 8, 16 }, "
|
||||
"rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]")
|
||||
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
|
||||
);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
@ -202,6 +203,7 @@ gst_osssink_init (GstOssSink * osssink)
|
|||
(&osssink_sink_factory), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (osssink), osssink->sinkpad);
|
||||
gst_pad_set_link_function (osssink->sinkpad, gst_osssink_sinkconnect);
|
||||
gst_pad_set_getcaps_function (osssink->sinkpad, gst_osssink_getcaps);
|
||||
gst_pad_set_fixate_function (osssink->sinkpad, gst_osssink_sink_fixate);
|
||||
gst_pad_set_convert_function (osssink->sinkpad, gst_osssink_convert);
|
||||
gst_pad_set_query_function (osssink->sinkpad, gst_osssink_sink_query);
|
||||
|
@ -256,6 +258,23 @@ gst_osssink_sink_fixate (GstPad * pad, const GstCaps * caps)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_osssink_getcaps (GstPad * pad)
|
||||
{
|
||||
GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
||||
GstCaps *caps;
|
||||
|
||||
gst_osselement_probe_caps (GST_OSSELEMENT (osssink));
|
||||
|
||||
if (GST_OSSELEMENT (osssink)->probed_caps == NULL) {
|
||||
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
||||
} else {
|
||||
caps = gst_caps_copy (GST_OSSELEMENT (osssink)->probed_caps);
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_osssink_sinkconnect (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ static GstStaticPadTemplate osssrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
"signed = (boolean) { TRUE, FALSE }, "
|
||||
"width = (int) { 8, 16 }, "
|
||||
"depth = (int) { 8, 16 }, "
|
||||
"rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]")
|
||||
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
|
||||
);
|
||||
|
||||
static void gst_osssrc_base_init (gpointer g_class);
|
||||
|
@ -76,6 +76,7 @@ static void gst_osssrc_dispose (GObject * object);
|
|||
|
||||
static GstPadLinkReturn gst_osssrc_srcconnect (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static GstCaps *gst_osssrc_getcaps (GstPad * pad);
|
||||
static const GstFormat *gst_osssrc_get_formats (GstPad * pad);
|
||||
static gboolean gst_osssrc_convert (GstPad * pad,
|
||||
GstFormat src_format, gint64 src_value,
|
||||
|
@ -176,6 +177,7 @@ gst_osssrc_init (GstOssSrc * osssrc)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&osssrc_src_factory), "src");
|
||||
gst_pad_set_get_function (osssrc->srcpad, gst_osssrc_get);
|
||||
gst_pad_set_getcaps_function (osssrc->srcpad, gst_osssrc_getcaps);
|
||||
gst_pad_set_link_function (osssrc->srcpad, gst_osssrc_srcconnect);
|
||||
gst_pad_set_convert_function (osssrc->srcpad, gst_osssrc_convert);
|
||||
gst_pad_set_formats_function (osssrc->srcpad, gst_osssrc_get_formats);
|
||||
|
@ -184,7 +186,6 @@ gst_osssrc_init (GstOssSrc * osssrc)
|
|||
gst_pad_set_query_function (osssrc->srcpad, gst_osssrc_src_query);
|
||||
gst_pad_set_query_type_function (osssrc->srcpad, gst_osssrc_get_query_types);
|
||||
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
|
||||
|
||||
osssrc->buffersize = 4096;
|
||||
|
@ -208,6 +209,25 @@ gst_osssrc_dispose (GObject * object)
|
|||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_osssrc_getcaps (GstPad * pad)
|
||||
{
|
||||
GstOssSrc *src;
|
||||
GstCaps *caps;
|
||||
|
||||
src = GST_OSSSRC (gst_pad_get_parent (pad));
|
||||
|
||||
gst_osselement_probe_caps (GST_OSSELEMENT (src));
|
||||
|
||||
if (GST_OSSELEMENT (src)->probed_caps == NULL) {
|
||||
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
||||
} else {
|
||||
caps = gst_caps_copy (GST_OSSELEMENT (src)->probed_caps);
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_osssrc_srcconnect (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue