mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
Merge branch 'master' into 0.11
Conflicts: ext/a52dec/gsta52dec.c ext/a52dec/gsta52dec.h ext/lame/gstlame.c ext/lame/gstlame.h ext/lame/gstlamemp3enc.c ext/mad/gstmad.c ext/mad/gstmad.h gst/mpegaudioparse/gstmpegaudioparse.c gst/mpegstream/gstdvddemux.c gst/realmedia/rdtdepay.c po/es.po po/lv.po po/sr.po
This commit is contained in:
commit
31063f0098
18 changed files with 820 additions and 465 deletions
|
@ -3,12 +3,15 @@ plugin_LTLIBRARIES = libgsta52dec.la
|
|||
libgsta52dec_la_SOURCES = gsta52dec.c
|
||||
libgsta52dec_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(ORC_CFLAGS) \
|
||||
$(A52DEC_CFLAGS)
|
||||
libgsta52dec_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) \
|
||||
-lgstaudio-$(GST_MAJORMINOR) \
|
||||
$(GST_BASE_LIBS) \
|
||||
$(GST_LIBS) \
|
||||
-lgstaudio-$(GST_MAJORMINOR) \
|
||||
$(ORC_LIBS) \
|
||||
$(A52DEC_LIBS)
|
||||
libgsta52dec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* SECTION:element-a52dec
|
||||
*
|
||||
* Dolby Digital (AC-3) audio decoder.
|
||||
*
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch line</title>
|
||||
* |[
|
||||
|
@ -88,17 +88,20 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
);
|
||||
|
||||
#define gst_a52dec_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstA52Dec, gst_a52dec, GST_TYPE_ELEMENT);
|
||||
G_DEFINE_TYPE (GstA52Dec, gst_a52dec, GST_TYPE_AUDIO_DECODER);
|
||||
|
||||
static gboolean gst_a52dec_start (GstAudioDecoder * dec);
|
||||
static gboolean gst_a52dec_stop (GstAudioDecoder * dec);
|
||||
static gboolean gst_a52dec_set_format (GstAudioDecoder * bdec, GstCaps * caps);
|
||||
static gboolean gst_a52dec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||
gint * offset, gint * length);
|
||||
static GstFlowReturn gst_a52dec_handle_frame (GstAudioDecoder * dec,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_a52dec_pre_push (GstAudioDecoder * bdec,
|
||||
GstBuffer ** buffer);
|
||||
|
||||
static GstFlowReturn gst_a52dec_chain (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_a52dec_chain_raw (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buf);
|
||||
static gboolean gst_a52dec_sink_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
static GstStateChangeReturn gst_a52dec_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static void gst_a52dec_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_a52dec_get_property (GObject * object, guint prop_id,
|
||||
|
@ -132,15 +135,22 @@ gst_a52dec_class_init (GstA52DecClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstAudioDecoderClass *gstbase_class;
|
||||
guint cpuflags;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbase_class = (GstAudioDecoderClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_a52dec_set_property;
|
||||
gobject_class->get_property = gst_a52dec_get_property;
|
||||
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_a52dec_change_state);
|
||||
gstbase_class->start = GST_DEBUG_FUNCPTR (gst_a52dec_start);
|
||||
gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_a52dec_stop);
|
||||
gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_a52dec_set_format);
|
||||
gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_a52dec_parse);
|
||||
gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_a52dec_handle_frame);
|
||||
gstbase_class->pre_push = GST_DEBUG_FUNCPTR (gst_a52dec_pre_push);
|
||||
|
||||
/**
|
||||
* GstA52Dec::drc
|
||||
|
@ -159,7 +169,7 @@ gst_a52dec_class_init (GstA52DecClass * klass)
|
|||
*
|
||||
* Force a particular output channel configuration from the decoder. By default,
|
||||
* the channel downmix (if any) is chosen automatically based on the downstream
|
||||
* capabilities of the pipeline.
|
||||
* capabilities of the pipeline.
|
||||
*/
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
|
||||
g_param_spec_enum ("mode", "Decoder Mode", "Decoding Mode (default 3f2r)",
|
||||
|
@ -213,21 +223,114 @@ gst_a52dec_class_init (GstA52DecClass * klass)
|
|||
static void
|
||||
gst_a52dec_init (GstA52Dec * a52dec)
|
||||
{
|
||||
/* create the sink and src pads */
|
||||
a52dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
|
||||
gst_pad_set_chain_function (a52dec->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_a52dec_chain));
|
||||
gst_pad_set_event_function (a52dec->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_a52dec_sink_event));
|
||||
gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->sinkpad);
|
||||
|
||||
a52dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->srcpad);
|
||||
|
||||
a52dec->request_channels = A52_CHANNEL;
|
||||
a52dec->dynamic_range_compression = FALSE;
|
||||
|
||||
gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED);
|
||||
a52dec->state = NULL;
|
||||
a52dec->samples = NULL;
|
||||
|
||||
/* retrieve and intercept base class chain.
|
||||
* Quite HACKish, but that's dvd specs/caps for you,
|
||||
* since one buffer needs to be split into 2 frames */
|
||||
a52dec->base_chain = GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (a52dec));
|
||||
gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (a52dec),
|
||||
GST_DEBUG_FUNCPTR (gst_a52dec_chain));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_start (GstAudioDecoder * dec)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (dec);
|
||||
GstA52DecClass *klass;
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "start");
|
||||
|
||||
klass = GST_A52DEC_CLASS (G_OBJECT_GET_CLASS (a52dec));
|
||||
a52dec->state = a52_init (klass->a52_cpuflags);
|
||||
|
||||
if (!a52dec->state) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), LIBRARY, INIT, (NULL),
|
||||
("failed to initialize a52 state"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
a52dec->samples = a52_samples (a52dec->state);
|
||||
a52dec->bit_rate = -1;
|
||||
a52dec->sample_rate = -1;
|
||||
a52dec->stream_channels = A52_CHANNEL;
|
||||
a52dec->using_channels = A52_CHANNEL;
|
||||
a52dec->level = 1;
|
||||
a52dec->bias = 0;
|
||||
a52dec->flag_update = TRUE;
|
||||
|
||||
/* call upon legacy upstream byte support (e.g. seeking) */
|
||||
gst_audio_decoder_set_byte_time (dec, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_stop (GstAudioDecoder * dec)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (dec);
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "stop");
|
||||
|
||||
a52dec->samples = NULL;
|
||||
if (a52dec->state) {
|
||||
a52_free (a52dec->state);
|
||||
a52dec->state = NULL;
|
||||
}
|
||||
if (a52dec->pending_tags) {
|
||||
gst_tag_list_free (a52dec->pending_tags);
|
||||
a52dec->pending_tags = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
|
||||
gint * _offset, gint * len)
|
||||
{
|
||||
GstA52Dec *a52dec;
|
||||
const guint8 *data;
|
||||
gint av, size;
|
||||
gint length = 0, flags, sample_rate, bit_rate;
|
||||
GstFlowReturn result = GST_FLOW_EOS;
|
||||
|
||||
a52dec = GST_A52DEC (bdec);
|
||||
|
||||
size = av = gst_adapter_available (adapter);
|
||||
data = (const guint8 *) gst_adapter_map (adapter, av);
|
||||
|
||||
/* find and read header */
|
||||
bit_rate = a52dec->bit_rate;
|
||||
sample_rate = a52dec->sample_rate;
|
||||
flags = 0;
|
||||
while (av >= 7) {
|
||||
length = a52_syncinfo ((guint8 *) data, &flags, &sample_rate, &bit_rate);
|
||||
|
||||
if (length == 0) {
|
||||
/* shift window to re-find sync */
|
||||
data++;
|
||||
size--;
|
||||
} else if (length <= size) {
|
||||
GST_LOG_OBJECT (a52dec, "Sync: frame size %d", length);
|
||||
result = GST_FLOW_OK;
|
||||
break;
|
||||
} else {
|
||||
GST_LOG_OBJECT (a52dec, "Not enough data available (needed %d had %d)",
|
||||
length, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gst_adapter_unmap (adapter);
|
||||
|
||||
*_offset = av - size;
|
||||
*len = length;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gint
|
||||
|
@ -310,119 +413,15 @@ gst_a52dec_channels (int flags, GstAudioChannelPosition * pos)
|
|||
return chans;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_queued (GstA52Dec * dec)
|
||||
{
|
||||
g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
|
||||
g_list_free (dec->queued);
|
||||
dec->queued = NULL;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
flush_queued (GstA52Dec * dec)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
while (dec->queued) {
|
||||
GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
|
||||
|
||||
GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %"
|
||||
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||
|
||||
/* iterate ouput queue an push downstream */
|
||||
ret = gst_pad_push (dec->srcpad, buf);
|
||||
|
||||
dec->queued = g_list_delete_link (dec->queued, dec->queued);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_drain (GstA52Dec * dec)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
if (dec->segment.rate < 0.0) {
|
||||
/* if we have some queued frames for reverse playback, flush
|
||||
* them now */
|
||||
ret = flush_queued (dec);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_push (GstA52Dec * a52dec,
|
||||
GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
int chans, n, c;
|
||||
GstFlowReturn result;
|
||||
sample_t *data;
|
||||
|
||||
flags &= (A52_CHANNEL_MASK | A52_LFE);
|
||||
if (!(chans = gst_a52dec_channels (flags, NULL)))
|
||||
goto no_channels;
|
||||
|
||||
buf = gst_buffer_new_allocate (NULL, 256 * chans * (SAMPLE_WIDTH / 8), 0);
|
||||
|
||||
data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
|
||||
for (n = 0; n < 256; n++) {
|
||||
for (c = 0; c < chans; c++) {
|
||||
data[n * chans + c] = samples[c * 256 + n];
|
||||
}
|
||||
}
|
||||
gst_audio_reorder_channels (data, 256 * chans * (SAMPLE_WIDTH / 8),
|
||||
(SAMPLE_WIDTH == 64) ? GST_AUDIO_FORMAT_F64 : GST_AUDIO_FORMAT_F32, chans,
|
||||
a52dec->from, a52dec->to);
|
||||
gst_buffer_unmap (buf, data, -1);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = timestamp;
|
||||
GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate;
|
||||
|
||||
result = GST_FLOW_OK;
|
||||
if ((buf = gst_audio_buffer_clip (buf, &a52dec->segment,
|
||||
a52dec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) {
|
||||
/* set discont when needed */
|
||||
if (a52dec->discont) {
|
||||
GST_LOG_OBJECT (a52dec, "marking DISCONT");
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
|
||||
a52dec->discont = FALSE;
|
||||
}
|
||||
|
||||
if (a52dec->segment.rate > 0.0) {
|
||||
GST_DEBUG_OBJECT (a52dec,
|
||||
"Pushing buffer with ts %" GST_TIME_FORMAT " duration %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||
|
||||
result = gst_pad_push (srcpad, buf);
|
||||
} else {
|
||||
/* reverse playback, queue frame till later when we get a discont. */
|
||||
GST_DEBUG_OBJECT (a52dec, "queued frame");
|
||||
a52dec->queued = g_list_prepend (a52dec->queued, buf);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
/* ERRORS */
|
||||
no_channels:
|
||||
{
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL),
|
||||
("invalid channel flags: %d", flags));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_reneg (GstA52Dec * a52dec, GstPad * pad)
|
||||
gst_a52dec_reneg (GstA52Dec * a52dec)
|
||||
{
|
||||
gint channels;
|
||||
GstCaps *caps = NULL;
|
||||
gboolean result = FALSE;
|
||||
GstAudioChannelPosition from[6], to[6];
|
||||
|
||||
channels = gst_a52dec_channels (a52dec->using_channels, a52dec->from);
|
||||
channels = gst_a52dec_channels (a52dec->using_channels, from);
|
||||
|
||||
if (!channels)
|
||||
goto done;
|
||||
|
@ -430,8 +429,10 @@ gst_a52dec_reneg (GstA52Dec * a52dec, GstPad * pad)
|
|||
GST_INFO_OBJECT (a52dec, "reneg channels:%d rate:%d",
|
||||
channels, a52dec->sample_rate);
|
||||
|
||||
memcpy (a52dec->to, a52dec->from, sizeof (a52dec->from));
|
||||
gst_audio_channel_positions_to_valid_order (a52dec->to, channels);
|
||||
memcpy (to, from, sizeof (GstAudioChannelPosition) * channels);
|
||||
gst_audio_channel_positions_to_valid_order (to, channels);
|
||||
gst_audio_get_channel_reorder_map (channels, from, to,
|
||||
a52dec->channel_reorder_map);
|
||||
|
||||
caps = gst_caps_new_simple ("audio/x-raw",
|
||||
"format", G_TYPE_STRING, SAMPLE_FORMAT,
|
||||
|
@ -441,15 +442,13 @@ gst_a52dec_reneg (GstA52Dec * a52dec, GstPad * pad)
|
|||
|
||||
if (channels > 1) {
|
||||
guint64 channel_mask = 0;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
channel_mask |= G_GUINT64_CONSTANT (1) << a52dec->to[i];
|
||||
gst_audio_channel_positions_to_mask (to, channels, &channel_mask);
|
||||
gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!gst_pad_set_caps (pad, caps))
|
||||
if (!gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (a52dec), caps))
|
||||
goto done;
|
||||
|
||||
result = TRUE;
|
||||
|
@ -460,113 +459,69 @@ done:
|
|||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_sink_setcaps (GstA52Dec * a52dec, GstCaps * caps)
|
||||
{
|
||||
GstStructure *structure;
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (structure && gst_structure_has_name (structure, "audio/x-private1-ac3"))
|
||||
a52dec->dvdmode = TRUE;
|
||||
else
|
||||
a52dec->dvdmode = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (parent);
|
||||
gboolean ret = FALSE;
|
||||
|
||||
GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
gst_event_parse_caps (event, &caps);
|
||||
|
||||
ret = gst_a52dec_sink_setcaps (a52dec, caps);
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
GstSegment seg;
|
||||
|
||||
gst_event_copy_segment (event, &seg);
|
||||
|
||||
/* drain queued buffers before activating the segment so that we can clip
|
||||
* against the old segment first */
|
||||
gst_a52dec_drain (a52dec);
|
||||
|
||||
if (seg.format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (seg.start)) {
|
||||
GST_WARNING ("No time in newsegment event %p (format is %s)",
|
||||
event, gst_format_get_name (seg.format));
|
||||
gst_event_unref (event);
|
||||
a52dec->sent_segment = FALSE;
|
||||
/* set some dummy values, FIXME: do proper conversion */
|
||||
a52dec->time = seg.start = seg.position = 0;
|
||||
seg.format = GST_FORMAT_TIME;
|
||||
seg.stop = -1;
|
||||
} else {
|
||||
a52dec->time = seg.start;
|
||||
a52dec->sent_segment = TRUE;
|
||||
GST_DEBUG_OBJECT (a52dec, "Pushing segment %" GST_SEGMENT_FORMAT, &seg);
|
||||
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
}
|
||||
a52dec->segment = seg;
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_TAG:
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
break;
|
||||
case GST_EVENT_EOS:
|
||||
gst_a52dec_drain (a52dec);
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
break;
|
||||
case GST_EVENT_FLUSH_START:
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
break;
|
||||
case GST_EVENT_FLUSH_STOP:
|
||||
if (a52dec->cache) {
|
||||
gst_buffer_unref (a52dec->cache);
|
||||
a52dec->cache = NULL;
|
||||
}
|
||||
clear_queued (a52dec);
|
||||
gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED);
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
break;
|
||||
default:
|
||||
ret = gst_pad_push_event (a52dec->srcpad, event);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_a52dec_update_streaminfo (GstA52Dec * a52dec)
|
||||
{
|
||||
GstTagList *taglist;
|
||||
|
||||
taglist = gst_tag_list_new (GST_TAG_AUDIO_CODEC, "Dolby Digital (AC-3)",
|
||||
GST_TAG_BITRATE, (guint) a52dec->bit_rate, NULL);
|
||||
taglist = gst_tag_list_new_empty ();
|
||||
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_BITRATE,
|
||||
(guint) a52dec->bit_rate, NULL);
|
||||
|
||||
gst_pad_push_event (GST_PAD (a52dec->srcpad), gst_event_new_tag (taglist));
|
||||
if (a52dec->pending_tags) {
|
||||
gst_tag_list_free (a52dec->pending_tags);
|
||||
a52dec->pending_tags = NULL;
|
||||
}
|
||||
|
||||
a52dec->pending_tags = taglist;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
||||
guint length, gint flags, gint sample_rate, gint bit_rate)
|
||||
gst_a52dec_pre_push (GstAudioDecoder * bdec, GstBuffer ** buffer)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (bdec);
|
||||
|
||||
if (G_UNLIKELY (a52dec->pending_tags)) {
|
||||
gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (a52dec),
|
||||
gst_event_new_tag (a52dec->pending_tags));
|
||||
a52dec->pending_tags = NULL;
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer)
|
||||
{
|
||||
GstA52Dec *a52dec;
|
||||
gint channels, i;
|
||||
gboolean need_reneg = FALSE;
|
||||
gint chans;
|
||||
gint length = 0, flags, sample_rate, bit_rate;
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
GstBuffer *outbuf;
|
||||
const gint num_blocks = 6;
|
||||
|
||||
a52dec = GST_A52DEC (bdec);
|
||||
|
||||
/* no fancy draining */
|
||||
if (G_UNLIKELY (!buffer))
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* parsed stuff already, so this should work out fine */
|
||||
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
|
||||
g_assert (size >= 7);
|
||||
|
||||
/* re-obtain some sync header info,
|
||||
* should be same as during _parse and could also be cached there,
|
||||
* but anyway ... */
|
||||
bit_rate = a52dec->bit_rate;
|
||||
sample_rate = a52dec->sample_rate;
|
||||
flags = 0;
|
||||
length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate);
|
||||
g_assert (length == size);
|
||||
|
||||
/* update stream information, renegotiate or re-streaminfo if needed */
|
||||
need_reneg = FALSE;
|
||||
|
@ -585,8 +540,8 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
|||
}
|
||||
|
||||
/* If we haven't had an explicit number of channels chosen through properties
|
||||
* at this point, choose what to downmix to now, based on what the peer will
|
||||
* accept - this allows a52dec to do downmixing in preference to a
|
||||
* at this point, choose what to downmix to now, based on what the peer will
|
||||
* accept - this allows a52dec to do downmixing in preference to a
|
||||
* downstream element such as audioconvert.
|
||||
*/
|
||||
if (a52dec->request_channels != A52_CHANNEL) {
|
||||
|
@ -596,7 +551,7 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
|||
|
||||
a52dec->flag_update = FALSE;
|
||||
|
||||
caps = gst_pad_get_allowed_caps (a52dec->srcpad);
|
||||
caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (a52dec));
|
||||
if (caps && gst_caps_get_size (caps) > 0) {
|
||||
GstCaps *copy = gst_caps_copy_nth (caps, 0);
|
||||
GstStructure *structure = gst_caps_get_structure (copy, 0);
|
||||
|
@ -610,13 +565,13 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
|||
A52_3F2R | A52_LFE,
|
||||
};
|
||||
|
||||
/* Prefer the original number of channels, but fixate to something
|
||||
/* Prefer the original number of channels, but fixate to something
|
||||
* preferred (first in the caps) downstream if possible.
|
||||
*/
|
||||
gst_structure_fixate_field_nearest_int (structure, "channels",
|
||||
flags ? gst_a52dec_channels (flags, NULL) : 6);
|
||||
gst_structure_get_int (structure, "channels", &channels);
|
||||
if (channels <= 6)
|
||||
if (gst_structure_get_int (structure, "channels", &channels)
|
||||
&& channels <= 6)
|
||||
flags = a52_channels[channels - 1];
|
||||
else
|
||||
flags = a52_channels[5];
|
||||
|
@ -632,14 +587,18 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
|||
} else {
|
||||
flags = a52dec->using_channels;
|
||||
}
|
||||
|
||||
/* process */
|
||||
flags |= A52_ADJUST_LEVEL;
|
||||
a52dec->level = 1;
|
||||
if (a52_frame (a52dec->state, data, &flags, &a52dec->level, a52dec->bias)) {
|
||||
GST_WARNING ("a52_frame error");
|
||||
a52dec->discont = TRUE;
|
||||
return GST_FLOW_OK;
|
||||
gst_buffer_unmap (buffer, data, size);
|
||||
GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL),
|
||||
("a52_frame error"), result);
|
||||
goto exit;
|
||||
}
|
||||
gst_buffer_unmap (buffer, data, size);
|
||||
|
||||
channels = flags & (A52_CHANNEL_MASK | A52_LFE);
|
||||
if (a52dec->using_channels != channels) {
|
||||
need_reneg = TRUE;
|
||||
|
@ -648,57 +607,97 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
|
|||
|
||||
/* negotiate if required */
|
||||
if (need_reneg) {
|
||||
GST_DEBUG ("a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d",
|
||||
GST_DEBUG_OBJECT (a52dec,
|
||||
"a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d",
|
||||
a52dec->sample_rate, a52dec->stream_channels, a52dec->using_channels);
|
||||
if (!gst_a52dec_reneg (a52dec, a52dec->srcpad)) {
|
||||
GST_ELEMENT_ERROR (a52dec, CORE, NEGOTIATION, (NULL), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (!gst_a52dec_reneg (a52dec))
|
||||
goto failed_negotiation;
|
||||
}
|
||||
|
||||
if (a52dec->dynamic_range_compression == FALSE) {
|
||||
a52_dynrng (a52dec->state, NULL, NULL);
|
||||
}
|
||||
|
||||
/* each frame consists of 6 blocks */
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (a52_block (a52dec->state)) {
|
||||
/* ignore errors but mark a discont */
|
||||
GST_WARNING ("a52_block error %d", i);
|
||||
a52dec->discont = TRUE;
|
||||
} else {
|
||||
GstFlowReturn ret;
|
||||
flags &= (A52_CHANNEL_MASK | A52_LFE);
|
||||
chans = gst_a52dec_channels (flags, NULL);
|
||||
if (!chans)
|
||||
goto invalid_flags;
|
||||
|
||||
/* push on */
|
||||
ret = gst_a52dec_push (a52dec, a52dec->srcpad, a52dec->using_channels,
|
||||
a52dec->samples, a52dec->time);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
/* handle decoded data;
|
||||
* each frame has 6 blocks, one block is 256 samples, ea */
|
||||
outbuf =
|
||||
gst_buffer_new_and_alloc (256 * chans * (SAMPLE_WIDTH / 8) * num_blocks);
|
||||
|
||||
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE);
|
||||
{
|
||||
guint8 *ptr = data;
|
||||
for (i = 0; i < num_blocks; i++) {
|
||||
if (a52_block (a52dec->state)) {
|
||||
/* also marks discont */
|
||||
GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL),
|
||||
("error decoding block %d", i), result);
|
||||
if (result != GST_FLOW_OK) {
|
||||
gst_buffer_unmap (outbuf, data, size);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
gint n, c;
|
||||
gint *reorder_map = a52dec->channel_reorder_map;
|
||||
|
||||
for (n = 0; n < 256; n++) {
|
||||
for (c = 0; c < chans; c++) {
|
||||
((sample_t *) ptr)[reorder_map[n] * chans + c] =
|
||||
a52dec->samples[c * 256 + n];
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr += 256 * chans * (SAMPLE_WIDTH / 8);
|
||||
}
|
||||
a52dec->time += 256 * GST_SECOND / a52dec->sample_rate;
|
||||
}
|
||||
gst_buffer_unmap (outbuf, data, size);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
result = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
|
||||
|
||||
exit:
|
||||
return result;
|
||||
|
||||
/* ERRORS */
|
||||
failed_negotiation:
|
||||
{
|
||||
GST_ELEMENT_ERROR (a52dec, CORE, NEGOTIATION, (NULL), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
invalid_flags:
|
||||
{
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL),
|
||||
("Invalid channel flags: %d", flags));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_a52dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (bdec);
|
||||
GstStructure *structure;
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (structure && gst_structure_has_name (structure, "audio/x-private1-ac3"))
|
||||
a52dec->dvdmode = TRUE;
|
||||
else
|
||||
a52dec->dvdmode = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||
{
|
||||
GstA52Dec *a52dec = GST_A52DEC (parent);
|
||||
GstFlowReturn ret;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
gint first_access;
|
||||
|
||||
if (GST_BUFFER_IS_DISCONT (buf)) {
|
||||
GST_LOG_OBJECT (a52dec, "received DISCONT");
|
||||
gst_a52dec_drain (a52dec);
|
||||
/* clear cache on discont and mark a discont in the element */
|
||||
if (a52dec->cache) {
|
||||
gst_buffer_unref (a52dec->cache);
|
||||
a52dec->cache = NULL;
|
||||
}
|
||||
a52dec->discont = TRUE;
|
||||
}
|
||||
|
||||
if (a52dec->dvdmode) {
|
||||
gsize size;
|
||||
guint8 data[2];
|
||||
|
@ -724,9 +723,11 @@ gst_a52dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|||
|
||||
subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
|
||||
GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
|
||||
ret = gst_a52dec_chain_raw (pad, parent, subbuf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
ret = a52dec->base_chain (pad, parent, subbuf);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unref (buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
len = size - offset;
|
||||
|
@ -735,23 +736,23 @@ gst_a52dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|||
subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
|
||||
GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
ret = gst_a52dec_chain_raw (pad, parent, subbuf);
|
||||
ret = a52dec->base_chain (pad, parent, subbuf);
|
||||
}
|
||||
gst_buffer_unref (buf);
|
||||
} else {
|
||||
/* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
|
||||
subbuf =
|
||||
gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset,
|
||||
size - offset);
|
||||
GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
|
||||
ret = gst_a52dec_chain_raw (pad, parent, subbuf);
|
||||
ret = a52dec->base_chain (pad, parent, subbuf);
|
||||
}
|
||||
} else {
|
||||
gst_buffer_ref (buf);
|
||||
ret = gst_a52dec_chain_raw (pad, parent, buf);
|
||||
ret = a52dec->base_chain (pad, parent, buf);
|
||||
}
|
||||
|
||||
done:
|
||||
gst_buffer_unref (buf);
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
|
@ -771,155 +772,6 @@ bad_first_access_parameter:
|
|||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_a52dec_chain_raw (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||
{
|
||||
GstA52Dec *a52dec;
|
||||
guint8 *bdata, *data;
|
||||
gsize bsize, size;
|
||||
gint length = 0, flags, sample_rate, bit_rate;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
|
||||
a52dec = GST_A52DEC (parent);
|
||||
|
||||
if (!a52dec->sent_segment) {
|
||||
GstSegment segment;
|
||||
|
||||
/* Create a basic segment. Usually, we'll get a new-segment sent by
|
||||
* another element that will know more information (a demuxer). If we're
|
||||
* just looking at a raw AC3 stream, we won't - so we need to send one
|
||||
* here, but we don't know much info, so just send a minimal TIME
|
||||
* new-segment event
|
||||
*/
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
gst_pad_push_event (a52dec->srcpad, gst_event_new_segment (&segment));
|
||||
a52dec->sent_segment = TRUE;
|
||||
}
|
||||
|
||||
/* merge with cache, if any. Also make sure timestamps match */
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
a52dec->time = GST_BUFFER_TIMESTAMP (buf);
|
||||
GST_DEBUG_OBJECT (a52dec,
|
||||
"Received buffer with ts %" GST_TIME_FORMAT " duration %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||
}
|
||||
|
||||
if (a52dec->cache) {
|
||||
buf = gst_buffer_join (a52dec->cache, buf);
|
||||
a52dec->cache = NULL;
|
||||
}
|
||||
bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
|
||||
|
||||
data = bdata;
|
||||
size = bsize;
|
||||
|
||||
/* find and read header */
|
||||
bit_rate = a52dec->bit_rate;
|
||||
sample_rate = a52dec->sample_rate;
|
||||
flags = 0;
|
||||
while (size >= 7) {
|
||||
length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate);
|
||||
|
||||
if (length == 0) {
|
||||
/* no sync */
|
||||
data++;
|
||||
size--;
|
||||
} else if (length <= size) {
|
||||
GST_DEBUG ("Sync: %d", length);
|
||||
|
||||
if (flags != a52dec->prev_flags)
|
||||
a52dec->flag_update = TRUE;
|
||||
a52dec->prev_flags = flags;
|
||||
|
||||
result = gst_a52dec_handle_frame (a52dec, data,
|
||||
length, flags, sample_rate, bit_rate);
|
||||
if (result != GST_FLOW_OK) {
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
size -= length;
|
||||
data += length;
|
||||
} else {
|
||||
/* not enough data */
|
||||
GST_LOG ("Not enough data available");
|
||||
break;
|
||||
}
|
||||
}
|
||||
gst_buffer_unmap (buf, bdata, bsize);
|
||||
|
||||
/* keep cache */
|
||||
if (length == 0) {
|
||||
GST_LOG ("No sync found");
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
a52dec->cache =
|
||||
gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, bsize - size, size);
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_a52dec_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstA52Dec *a52dec = GST_A52DEC (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:{
|
||||
GstA52DecClass *klass;
|
||||
|
||||
klass = GST_A52DEC_CLASS (G_OBJECT_GET_CLASS (a52dec));
|
||||
a52dec->state = a52_init (klass->a52_cpuflags);
|
||||
break;
|
||||
}
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
a52dec->samples = a52_samples (a52dec->state);
|
||||
a52dec->bit_rate = -1;
|
||||
a52dec->sample_rate = -1;
|
||||
a52dec->stream_channels = A52_CHANNEL;
|
||||
a52dec->using_channels = A52_CHANNEL;
|
||||
a52dec->level = 1;
|
||||
a52dec->bias = 0;
|
||||
a52dec->time = 0;
|
||||
a52dec->sent_segment = FALSE;
|
||||
a52dec->flag_update = TRUE;
|
||||
gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
a52dec->samples = NULL;
|
||||
if (a52dec->cache) {
|
||||
gst_buffer_unref (a52dec->cache);
|
||||
a52dec->cache = NULL;
|
||||
}
|
||||
clear_queued (a52dec);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
a52_free (a52dec->state);
|
||||
a52dec->state = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_a52dec_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/audio.h>
|
||||
#include <gst/audio/gstaudiodecoder.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -41,27 +42,22 @@ typedef struct _GstA52Dec GstA52Dec;
|
|||
typedef struct _GstA52DecClass GstA52DecClass;
|
||||
|
||||
struct _GstA52Dec {
|
||||
GstElement element;
|
||||
GstAudioDecoder element;
|
||||
|
||||
/* pads */
|
||||
GstPad *sinkpad,
|
||||
*srcpad;
|
||||
GstSegment segment;
|
||||
GstPadChainFunction base_chain;
|
||||
|
||||
gboolean dvdmode;
|
||||
gboolean sent_segment;
|
||||
gboolean discont;
|
||||
|
||||
gboolean flag_update;
|
||||
int prev_flags;
|
||||
|
||||
/* stream properties */
|
||||
int bit_rate;
|
||||
int sample_rate;
|
||||
int stream_channels;
|
||||
int request_channels;
|
||||
int using_channels;
|
||||
|
||||
GstAudioChannelPosition from[6], to[6];
|
||||
gint channel_reorder_map[6];
|
||||
|
||||
sample_t level;
|
||||
sample_t bias;
|
||||
|
@ -69,15 +65,11 @@ struct _GstA52Dec {
|
|||
sample_t *samples;
|
||||
a52_state_t *state;
|
||||
|
||||
GstBuffer *cache;
|
||||
GstClockTime time;
|
||||
|
||||
/* reverse */
|
||||
GList *queued;
|
||||
GstTagList *pending_tags;
|
||||
};
|
||||
|
||||
struct _GstA52DecClass {
|
||||
GstElementClass parent_class;
|
||||
GstAudioDecoderClass parent_class;
|
||||
|
||||
guint32 a52_cpuflags;
|
||||
};
|
||||
|
|
|
@ -523,15 +523,26 @@ gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title, gint angle)
|
|||
/* subtitle */
|
||||
for (i = 0; i < src->vts_file->vtsi_mat->nr_of_vts_subp_streams; i++) {
|
||||
const subp_attr_t *u;
|
||||
const video_attr_t *v;
|
||||
gint sid;
|
||||
|
||||
/* subpicture stream present? */
|
||||
if (pgc0 != NULL && (pgc0->subp_control[i] & 0x80000000) == 0)
|
||||
continue;
|
||||
|
||||
u = &src->vts_file->vtsi_mat->vts_subp_attr[i];
|
||||
v = &src->vts_file->vtsi_mat->vts_video_attr;
|
||||
|
||||
sid = i;
|
||||
if (pgc0 != NULL) {
|
||||
if (v->display_aspect_ratio == 0) /* 4:3 */
|
||||
sid = (pgc0->subp_control[i] >> 24) & 0x1f;
|
||||
else if (v->display_aspect_ratio == 3) /* 16:9 */
|
||||
sid = (pgc0->subp_control[i] >> 8) & 0x1f;
|
||||
}
|
||||
|
||||
if (u->type) {
|
||||
t = g_strdup_printf ("subtitle-%d-language", i);
|
||||
t = g_strdup_printf ("subtitle-%d-language", sid);
|
||||
lang_code[0] = (u->lang_code >> 8) & 0xff;
|
||||
lang_code[1] = u->lang_code & 0xff;
|
||||
gst_structure_set (s, t, G_TYPE_STRING, lang_code, NULL);
|
||||
|
@ -541,7 +552,7 @@ gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title, gint angle)
|
|||
}
|
||||
|
||||
GST_INFO_OBJECT (src, "[%02d] Subtitle %02d: lang='%s', type=%d",
|
||||
src->title + 1, i, lang_code, u->type);
|
||||
src->title + 1, sid, lang_code, u->type);
|
||||
}
|
||||
|
||||
src->title_lang_event_pending =
|
||||
|
@ -1591,7 +1602,8 @@ gst_dvd_read_src_goto_sector (GstDvdReadSrc * src, int angle)
|
|||
gint first = src->cur_pgc->cell_playback[cur].first_sector;
|
||||
gint last = src->cur_pgc->cell_playback[cur].last_sector;
|
||||
GST_DEBUG_OBJECT (src, "Cell %d sector bounds: %d %d", cur, first, last);
|
||||
if (seek_to >= first && seek_to <= last) {
|
||||
/* seeking to 0 should end up at first chapter in any case */
|
||||
if ((seek_to >= first && seek_to <= last) || (seek_to == 0 && i == 0)) {
|
||||
GST_DEBUG_OBJECT (src, "Seek target found in chapter %d", i);
|
||||
chapter = i;
|
||||
goto done;
|
||||
|
|
|
@ -2,9 +2,9 @@ plugin_LTLIBRARIES = libgstlame.la
|
|||
|
||||
libgstlame_la_SOURCES = gstlamemp3enc.c plugin.c
|
||||
libgstlame_la_CFLAGS = -DGST_USE_UNSTABLE_API \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS)
|
||||
libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) \
|
||||
-lgstaudio-$(GST_MAJORMINOR) $(GST_LIBS)
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS)
|
||||
libgstlame_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
|
||||
$(GST_BASE_LIBS) $(GST_LIBS) $(LAME_LIBS)
|
||||
libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstlame_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
|
|
|
@ -289,6 +289,11 @@ gst_lamemp3enc_start (GstAudioEncoder * enc)
|
|||
GstLameMP3Enc *lame = GST_LAMEMP3ENC (enc);
|
||||
|
||||
GST_DEBUG_OBJECT (lame, "start");
|
||||
|
||||
if (!lame->adapter)
|
||||
lame->adapter = gst_adapter_new ();
|
||||
gst_adapter_clear (lame->adapter);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -299,6 +304,11 @@ gst_lamemp3enc_stop (GstAudioEncoder * enc)
|
|||
|
||||
GST_DEBUG_OBJECT (lame, "stop");
|
||||
|
||||
if (lame->adapter) {
|
||||
g_object_unref (lame->adapter);
|
||||
lame->adapter = NULL;
|
||||
}
|
||||
|
||||
gst_lamemp3enc_release_memory (lame);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -334,6 +344,7 @@ gst_lamemp3enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
|
|||
"output samplerate %d is different from incoming samplerate %d",
|
||||
out_samplerate, lame->samplerate);
|
||||
}
|
||||
lame->out_samplerate = out_samplerate;
|
||||
|
||||
version = lame_get_version (lame->lgf);
|
||||
if (version == 0)
|
||||
|
@ -362,8 +373,10 @@ gst_lamemp3enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
|
|||
GST_SECOND, lame->samplerate);
|
||||
gst_audio_encoder_set_latency (enc, latency, latency);
|
||||
|
||||
if (tags)
|
||||
if (tags) {
|
||||
gst_audio_encoder_merge_tags (enc, tags, GST_TAG_MERGE_REPLACE);
|
||||
gst_tag_list_free (tags);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
@ -486,6 +499,204 @@ gst_lamemp3enc_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
}
|
||||
}
|
||||
|
||||
/* **** credits go to mpegaudioparse **** */
|
||||
|
||||
static const guint mp3types_bitrates[2][3][16] = {
|
||||
{
|
||||
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
|
||||
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
|
||||
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
|
||||
},
|
||||
{
|
||||
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
|
||||
},
|
||||
};
|
||||
|
||||
static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
|
||||
{22050, 24000, 16000},
|
||||
{11025, 12000, 8000}
|
||||
};
|
||||
|
||||
static inline guint
|
||||
mp3_type_frame_length_from_header (GstLameMP3Enc * lame, guint32 header,
|
||||
guint * put_version, guint * put_layer, guint * put_channels,
|
||||
guint * put_bitrate, guint * put_samplerate, guint * put_mode,
|
||||
guint * put_crc)
|
||||
{
|
||||
guint length;
|
||||
gulong mode, samplerate, bitrate, layer, channels, padding, crc;
|
||||
gulong version;
|
||||
gint lsf, mpg25;
|
||||
|
||||
if (header & (1 << 20)) {
|
||||
lsf = (header & (1 << 19)) ? 0 : 1;
|
||||
mpg25 = 0;
|
||||
} else {
|
||||
lsf = 1;
|
||||
mpg25 = 1;
|
||||
}
|
||||
|
||||
version = 1 + lsf + mpg25;
|
||||
|
||||
layer = 4 - ((header >> 17) & 0x3);
|
||||
|
||||
crc = (header >> 16) & 0x1;
|
||||
|
||||
bitrate = (header >> 12) & 0xF;
|
||||
bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
|
||||
/* The caller has ensured we have a valid header, so bitrate can't be
|
||||
zero here. */
|
||||
g_assert (bitrate != 0);
|
||||
|
||||
samplerate = (header >> 10) & 0x3;
|
||||
samplerate = mp3types_freqs[lsf + mpg25][samplerate];
|
||||
|
||||
padding = (header >> 9) & 0x1;
|
||||
|
||||
mode = (header >> 6) & 0x3;
|
||||
channels = (mode == 3) ? 1 : 2;
|
||||
|
||||
switch (layer) {
|
||||
case 1:
|
||||
length = 4 * ((bitrate * 12) / samplerate + padding);
|
||||
break;
|
||||
case 2:
|
||||
length = (bitrate * 144) / samplerate + padding;
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
length = (bitrate * 144) / (samplerate << lsf) + padding;
|
||||
break;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (lame, "Calculated mp3 frame length of %u bytes", length);
|
||||
GST_DEBUG_OBJECT (lame, "samplerate = %lu, bitrate = %lu, version = %lu, "
|
||||
"layer = %lu, channels = %lu", samplerate, bitrate, version,
|
||||
layer, channels);
|
||||
|
||||
if (put_version)
|
||||
*put_version = version;
|
||||
if (put_layer)
|
||||
*put_layer = layer;
|
||||
if (put_channels)
|
||||
*put_channels = channels;
|
||||
if (put_bitrate)
|
||||
*put_bitrate = bitrate;
|
||||
if (put_samplerate)
|
||||
*put_samplerate = samplerate;
|
||||
if (put_mode)
|
||||
*put_mode = mode;
|
||||
if (put_crc)
|
||||
*put_crc = crc;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mp3_sync_check (GstLameMP3Enc * lame, unsigned long head)
|
||||
{
|
||||
GST_DEBUG_OBJECT (lame, "checking mp3 header 0x%08lx", head);
|
||||
/* if it's not a valid sync */
|
||||
if ((head & 0xffe00000) != 0xffe00000) {
|
||||
GST_WARNING_OBJECT (lame, "invalid sync");
|
||||
return FALSE;
|
||||
}
|
||||
/* if it's an invalid MPEG version */
|
||||
if (((head >> 19) & 3) == 0x1) {
|
||||
GST_WARNING_OBJECT (lame, "invalid MPEG version: 0x%lx", (head >> 19) & 3);
|
||||
return FALSE;
|
||||
}
|
||||
/* if it's an invalid layer */
|
||||
if (!((head >> 17) & 3)) {
|
||||
GST_WARNING_OBJECT (lame, "invalid layer: 0x%lx", (head >> 17) & 3);
|
||||
return FALSE;
|
||||
}
|
||||
/* if it's an invalid bitrate */
|
||||
if (((head >> 12) & 0xf) == 0x0) {
|
||||
GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx."
|
||||
"Free format files are not supported yet", (head >> 12) & 0xf);
|
||||
return FALSE;
|
||||
}
|
||||
if (((head >> 12) & 0xf) == 0xf) {
|
||||
GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx", (head >> 12) & 0xf);
|
||||
return FALSE;
|
||||
}
|
||||
/* if it's an invalid samplerate */
|
||||
if (((head >> 10) & 0x3) == 0x3) {
|
||||
GST_WARNING_OBJECT (lame, "invalid samplerate: 0x%lx", (head >> 10) & 0x3);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((head & 0x3) == 0x2) {
|
||||
/* Ignore this as there are some files with emphasis 0x2 that can
|
||||
* be played fine. See BGO #537235 */
|
||||
GST_WARNING_OBJECT (lame, "invalid emphasis: 0x%lx", head & 0x3);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* **** end mpegaudioparse **** */
|
||||
|
||||
static GstFlowReturn
|
||||
gst_lamemp3enc_finish_frames (GstLameMP3Enc * lame)
|
||||
{
|
||||
gint av;
|
||||
guint header;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
|
||||
/* limited parsing, we don't expect to lose sync here */
|
||||
while ((result == GST_FLOW_OK) &&
|
||||
((av = gst_adapter_available (lame->adapter)) > 4)) {
|
||||
guint rate, version, layer, size;
|
||||
GstBuffer *mp3_buf;
|
||||
const guint8 *data;
|
||||
|
||||
data = gst_adapter_map (lame->adapter, 4);
|
||||
header = GST_READ_UINT32_BE (data);
|
||||
gst_adapter_unmap (lame->adapter);
|
||||
|
||||
if (!mp3_sync_check (lame, header))
|
||||
goto invalid_header;
|
||||
|
||||
size = mp3_type_frame_length_from_header (lame, header, &version, &layer,
|
||||
NULL, NULL, &rate, NULL, NULL);
|
||||
|
||||
if (G_UNLIKELY (layer != 3 || rate != lame->out_samplerate)) {
|
||||
GST_DEBUG_OBJECT (lame,
|
||||
"unexpected mp3 header with rate %u, version %u, layer %u",
|
||||
rate, version, layer);
|
||||
goto invalid_header;
|
||||
}
|
||||
|
||||
if (size > av) {
|
||||
/* pretty likely to occur when lame is holding back on us */
|
||||
GST_LOG_OBJECT (lame, "frame size %u (> %d)", size, av);
|
||||
break;
|
||||
}
|
||||
|
||||
/* should be ok now */
|
||||
mp3_buf = gst_adapter_take_buffer (lame->adapter, size);
|
||||
/* number of samples for MPEG-1, layer 3 */
|
||||
result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame),
|
||||
mp3_buf, version == 1 ? 1152 : 576);
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
|
||||
/* ERRORS */
|
||||
invalid_header:
|
||||
{
|
||||
GST_ELEMENT_ERROR (lame, STREAM, ENCODE,
|
||||
("invalid lame mp3 sync header %08X", header), (NULL));
|
||||
result = GST_FLOW_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push)
|
||||
{
|
||||
|
@ -493,6 +704,7 @@ gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push)
|
|||
gint size;
|
||||
guint8 *data;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
gint av;
|
||||
|
||||
if (!lame->lgf)
|
||||
return GST_FLOW_OK;
|
||||
|
@ -503,17 +715,30 @@ gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push)
|
|||
|
||||
if (size > 0) {
|
||||
gst_buffer_unmap (buf, data, size);
|
||||
if (push) {
|
||||
GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size);
|
||||
result =
|
||||
gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1);
|
||||
}
|
||||
GST_DEBUG_OBJECT (lame, "collecting final %d bytes", size);
|
||||
gst_adapter_push (lame->adapter, buf);
|
||||
} else {
|
||||
gst_buffer_unmap (buf, data, 0);
|
||||
GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push);
|
||||
gst_buffer_unref (buf);
|
||||
result = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
if (push) {
|
||||
result = gst_lamemp3enc_finish_frames (lame);
|
||||
} else {
|
||||
/* never mind */
|
||||
gst_adapter_clear (lame->adapter);
|
||||
}
|
||||
|
||||
/* either way, we expect nothing left */
|
||||
if ((av = gst_adapter_available (lame->adapter))) {
|
||||
/* should this be more fatal ?? */
|
||||
GST_WARNING_OBJECT (lame, "unparsed %d bytes left after flushing", av);
|
||||
/* clean up anyway */
|
||||
gst_adapter_clear (lame->adapter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -566,8 +791,11 @@ gst_lamemp3enc_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf)
|
|||
"to %d bytes of mp3", size, mp3_size);
|
||||
|
||||
if (G_LIKELY (mp3_size > 0)) {
|
||||
/* unfortunately lame does not provide frame delineated output,
|
||||
* so collect output and parse into frames ... */
|
||||
gst_buffer_unmap (mp3_buf, mp3_data, mp3_size);
|
||||
result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1);
|
||||
gst_adapter_push (lame->adapter, mp3_buf);
|
||||
result = gst_lamemp3enc_finish_frames (lame);
|
||||
} else {
|
||||
gst_buffer_unmap (mp3_buf, mp3_data, 0);
|
||||
if (mp3_size < 0) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/gstaudioencoder.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -54,6 +55,7 @@ struct _GstLameMP3Enc {
|
|||
|
||||
/*< private >*/
|
||||
gint samplerate;
|
||||
gint out_samplerate;
|
||||
gint num_channels;
|
||||
|
||||
/* properties */
|
||||
|
@ -65,6 +67,8 @@ struct _GstLameMP3Enc {
|
|||
gboolean mono;
|
||||
|
||||
lame_global_flags *lgf;
|
||||
|
||||
GstAdapter *adapter;
|
||||
};
|
||||
|
||||
struct _GstLameMP3EncClass {
|
||||
|
|
|
@ -3,11 +3,11 @@ plugin_LTLIBRARIES = libgstmad.la
|
|||
libgstmad_la_SOURCES = gstmad.c
|
||||
|
||||
libgstmad_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) \
|
||||
$(MAD_CFLAGS)
|
||||
libgstmad_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
|
||||
-lgstaudio-$(GST_MAJORMINOR) $(MAD_LIBS)
|
||||
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
|
||||
$(GST_BASE_LIBS) $(GST_LIBS) $(MAD_LIBS)
|
||||
libgstmad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstmad_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ static gboolean gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
|||
gint * offset, gint * length);
|
||||
static GstFlowReturn gst_mad_handle_frame (GstAudioDecoder * dec,
|
||||
GstBuffer * buffer);
|
||||
static gboolean gst_mad_event (GstAudioDecoder * dec, GstEvent * event);
|
||||
static void gst_mad_flush (GstAudioDecoder * dec, gboolean hard);
|
||||
|
||||
static void gst_mad_set_property (GObject * object, guint prop_id,
|
||||
|
@ -102,6 +103,13 @@ gst_mad_class_init (GstMadClass * klass)
|
|||
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame);
|
||||
base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush);
|
||||
|
||||
base_class->start = GST_DEBUG_FUNCPTR (gst_mad_start);
|
||||
base_class->stop = GST_DEBUG_FUNCPTR (gst_mad_stop);
|
||||
base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse);
|
||||
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame);
|
||||
base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush);
|
||||
base_class->event = GST_DEBUG_FUNCPTR (gst_mad_event);
|
||||
|
||||
gobject_class->set_property = gst_mad_set_property;
|
||||
gobject_class->get_property = gst_mad_get_property;
|
||||
|
||||
|
@ -159,6 +167,7 @@ gst_mad_start (GstAudioDecoder * dec)
|
|||
mad_stream_options (&mad->stream, options);
|
||||
mad->header.mode = -1;
|
||||
mad->header.emphasis = -1;
|
||||
mad->eos = FALSE;
|
||||
|
||||
/* call upon legacy upstream byte support (e.g. seeking) */
|
||||
gst_audio_decoder_set_byte_time (dec, TRUE);
|
||||
|
@ -269,7 +278,6 @@ gst_mad_check_caps_reset (GstMad * mad)
|
|||
}
|
||||
}
|
||||
|
||||
/* FIXME: does this work properly at all? filesrc ! mad ! pulsesink fails */
|
||||
static GstFlowReturn
|
||||
gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||
gint * _offset, gint * len)
|
||||
|
@ -281,6 +289,20 @@ gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
|||
|
||||
mad = GST_MAD (dec);
|
||||
|
||||
if (mad->eos) {
|
||||
/* This is one steaming hack right there.
|
||||
* mad will not decode the last frame if it is not followed by
|
||||
* a number of 0 bytes, due to some buffer overflow, which can
|
||||
* not be fixed for reasons I did not inquire into, see
|
||||
* http://www.mars.org/mailman/public/mad-dev/2001-May/000262.html
|
||||
*/
|
||||
GstBuffer *guard = gst_buffer_new_and_alloc (MAD_BUFFER_GUARD);
|
||||
gst_buffer_memset (guard, 0, 0, MAD_BUFFER_GUARD);
|
||||
GST_DEBUG_OBJECT (mad, "Discreetly stuffing %u zero bytes in the adapter",
|
||||
MAD_BUFFER_GUARD);
|
||||
gst_adapter_push (adapter, guard);
|
||||
}
|
||||
|
||||
/* we basically let mad library do parsing,
|
||||
* and translate that back to baseclass.
|
||||
* if a frame is found (and also decoded), subsequent handle_frame
|
||||
|
@ -472,6 +494,21 @@ gst_mad_flush (GstAudioDecoder * dec, gboolean hard)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mad_event (GstAudioDecoder * dec, GstEvent * event)
|
||||
{
|
||||
GstMad *mad;
|
||||
|
||||
mad = GST_MAD (dec);
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||
GST_DEBUG_OBJECT (mad, "We got EOS, will pad next time");
|
||||
mad->eos = TRUE;
|
||||
}
|
||||
|
||||
/* Let the base class do its usual thing */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mad_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
|
|
@ -46,7 +46,7 @@ typedef struct _GstMadClass GstMadClass;
|
|||
|
||||
struct _GstMad
|
||||
{
|
||||
GstAudioDecoder audiodecoder;
|
||||
GstAudioDecoder element;
|
||||
|
||||
/* state */
|
||||
struct mad_stream stream;
|
||||
|
@ -62,6 +62,8 @@ struct _GstMad
|
|||
gint times_pending;
|
||||
gboolean caps_set; /* used to keep track of whether to change/update caps */
|
||||
|
||||
gboolean eos;
|
||||
|
||||
/* properties */
|
||||
gboolean half;
|
||||
gboolean ignore_crc;
|
||||
|
@ -69,7 +71,7 @@ struct _GstMad
|
|||
|
||||
struct _GstMadClass
|
||||
{
|
||||
GstAudioDecoderClass audiodecoder_class;
|
||||
GstAudioDecoderClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_mad_get_type (void);
|
||||
|
|
|
@ -1 +1 @@
|
|||
noinst_HEADERS = gst-i18n-plugin.h gettext.h
|
||||
noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h
|
||||
|
|
135
gst-libs/gst/glib-compat-private.h
Normal file
135
gst-libs/gst/glib-compat-private.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* glib-compat.c
|
||||
* Functions copied from glib 2.10
|
||||
*
|
||||
* Copyright 2005 David Schleef <ds@schleef.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GLIB_COMPAT_PRIVATE_H__
|
||||
#define __GLIB_COMPAT_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,25,0)
|
||||
|
||||
#if defined (_MSC_VER) && !defined(_WIN64)
|
||||
typedef struct _stat32 GStatBuf;
|
||||
#else
|
||||
typedef struct stat GStatBuf;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
#define GLIB_HAS_GDATETIME
|
||||
#endif
|
||||
|
||||
/* See bug #651514 */
|
||||
#if GLIB_CHECK_VERSION(2,29,5)
|
||||
#define G_ATOMIC_POINTER_COMPARE_AND_EXCHANGE(a,b,c) \
|
||||
g_atomic_pointer_compare_and_exchange ((a),(b),(c))
|
||||
#define G_ATOMIC_INT_COMPARE_AND_EXCHANGE(a,b,c) \
|
||||
g_atomic_int_compare_and_exchange ((a),(b),(c))
|
||||
#else
|
||||
#define G_ATOMIC_POINTER_COMPARE_AND_EXCHANGE(a,b,c) \
|
||||
g_atomic_pointer_compare_and_exchange ((volatile gpointer *)(a),(b),(c))
|
||||
#define G_ATOMIC_INT_COMPARE_AND_EXCHANGE(a,b,c) \
|
||||
g_atomic_int_compare_and_exchange ((volatile int *)(a),(b),(c))
|
||||
#endif
|
||||
|
||||
/* See bug #651514 */
|
||||
#if GLIB_CHECK_VERSION(2,29,5)
|
||||
#define G_ATOMIC_INT_ADD(a,b) g_atomic_int_add ((a),(b))
|
||||
#else
|
||||
#define G_ATOMIC_INT_ADD(a,b) g_atomic_int_exchange_and_add ((a),(b))
|
||||
#endif
|
||||
|
||||
/* copies */
|
||||
|
||||
#if GLIB_CHECK_VERSION (2, 31, 0)
|
||||
#define g_mutex_new gst_g_mutex_new
|
||||
static inline GMutex *
|
||||
gst_g_mutex_new (void)
|
||||
{
|
||||
GMutex *mutex = g_slice_new (GMutex);
|
||||
g_mutex_init (mutex);
|
||||
return mutex;
|
||||
}
|
||||
#define g_mutex_free gst_g_mutex_free
|
||||
static inline void
|
||||
gst_g_mutex_free (GMutex *mutex)
|
||||
{
|
||||
g_mutex_clear (mutex);
|
||||
g_slice_free (GMutex, mutex);
|
||||
}
|
||||
#define g_static_rec_mutex_init gst_g_static_rec_mutex_init
|
||||
static inline void
|
||||
gst_g_static_rec_mutex_init (GStaticRecMutex *mutex)
|
||||
{
|
||||
static const GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
|
||||
|
||||
*mutex = init_mutex;
|
||||
}
|
||||
#define g_cond_new gst_g_cond_new
|
||||
static inline GCond *
|
||||
gst_g_cond_new (void)
|
||||
{
|
||||
GCond *cond = g_slice_new (GCond);
|
||||
g_cond_init (cond);
|
||||
return cond;
|
||||
}
|
||||
#define g_cond_free gst_g_cond_free
|
||||
static inline void
|
||||
gst_g_cond_free (GCond *cond)
|
||||
{
|
||||
g_cond_clear (cond);
|
||||
g_slice_free (GCond, cond);
|
||||
}
|
||||
#define g_cond_timed_wait gst_g_cond_timed_wait
|
||||
static inline gboolean
|
||||
gst_g_cond_timed_wait (GCond *cond, GMutex *mutex, GTimeVal *abs_time)
|
||||
{
|
||||
gint64 end_time;
|
||||
|
||||
if (abs_time == NULL) {
|
||||
g_cond_wait (cond, mutex);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
end_time = abs_time->tv_sec;
|
||||
end_time *= 1000000;
|
||||
end_time += abs_time->tv_usec;
|
||||
|
||||
/* would be nice if we had clock_rtoffset, but that didn't seem to
|
||||
* make it into the kernel yet...
|
||||
*/
|
||||
/* if CLOCK_MONOTONIC is not defined then g_get_montonic_time() and
|
||||
* g_get_real_time() are returning the same clock and we'd add ~0
|
||||
*/
|
||||
end_time += g_get_monotonic_time () - g_get_real_time ();
|
||||
return g_cond_wait_until (cond, mutex, end_time);
|
||||
}
|
||||
#endif /* GLIB_CHECK_VERSION (2, 31, 0) */
|
||||
|
||||
/* adaptations */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
|
@ -32,6 +32,10 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
|
||||
* with newer GLib versions (>= 2.31.0) */
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include <gst/gstutils.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <gst/riff/riff-media.h>
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
|
||||
* with newer GLib versions (>= 2.31.0) */
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "rademux.h"
|
||||
#include "rmdemux.h"
|
||||
#include "rmutils.h"
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
#include "rdtmanager.h"
|
||||
#include "rdtjitterbuffer.h"
|
||||
|
||||
#include <gst/glib-compat-private.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rdtmanager_debug);
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
|
||||
* with newer GLib versions (>= 2.31.0) */
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "rmdemux.h"
|
||||
#include "rmutils.h"
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
af az bg ca cs da de el en_GB es eu fi fr gl hu id it ja lt lv ms mt nb nl or pl pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN
|
||||
af az bg ca cs da de el en_GB eo es eu fi fr gl hu id it ja lt lv ms mt nb nl or pl pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN
|
||||
|
|
76
po/eo.po
Normal file
76
po/eo.po
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Esperanto translation for gst-plugins-ugly.
|
||||
# Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the gst-plugins-ugly package.
|
||||
# Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>, 2011.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gst-plugins-ugly 0.10.17.2\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
|
||||
"POT-Creation-Date: 2011-12-10 15:17+0000\n"
|
||||
"PO-Revision-Date: 2011-06-04 22:24+0200\n"
|
||||
"Last-Translator: Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>\n"
|
||||
"Language-Team: Esperanto <translation-team-eo@lists.sourceforge.net>\n"
|
||||
"Language: eo\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgid "Could not read from CD."
|
||||
msgstr "Ne eblis legi de la KD."
|
||||
|
||||
msgid "Could not open CD device for reading."
|
||||
msgstr "Ne eblis malfermi la KD-aparaton por legi."
|
||||
|
||||
msgid "Disc is not an Audio CD."
|
||||
msgstr "La disko ne estas son-KD."
|
||||
|
||||
msgid "Could not open DVD"
|
||||
msgstr "Ne eblis malfermi la DVD-n"
|
||||
|
||||
#, c-format
|
||||
msgid "Could not open DVD title %d"
|
||||
msgstr "Ne eblis malfermi la titolon \"%d\" de la DVD"
|
||||
|
||||
#, c-format
|
||||
msgid "Failed to go to chapter %d of DVD title %d"
|
||||
msgstr "Fiaksi iri al la ĉapitro %d de la DVD-titolo %d"
|
||||
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Could not open DVD title %d. Interactive titles are not supported by this "
|
||||
"element"
|
||||
msgstr ""
|
||||
"Ne eblis malfermi la DVD-titolon \"%d\". Interagaj titoloj ne estas "
|
||||
"suptenata de tiu elemento"
|
||||
|
||||
msgid ""
|
||||
"Could not read DVD. This may be because the DVD is encrypted and a DVD "
|
||||
"decryption library is not installed."
|
||||
msgstr ""
|
||||
"Ne eblis legi la DVD-n. Eble la DVD estas ĉifrita sed biblioteko por DVD-"
|
||||
"malĉifrado ne estas instalite."
|
||||
|
||||
msgid "Could not read DVD."
|
||||
msgstr "Ne eblis legi la DVD-n."
|
||||
|
||||
msgid "Failed to configure LAME encoder. Check your encoding parameters."
|
||||
msgstr "Fiaskis agordi la LAME-kodilon. Kontrolu viajn kodad-parametrojn."
|
||||
|
||||
#, c-format
|
||||
msgid ""
|
||||
"The requested bitrate %d kbit/s for property '%s' is not allowed. The "
|
||||
"bitrate was changed to %d kbit/s."
|
||||
msgstr ""
|
||||
"La petita bitrapido je %d kBit/s ne estas permesata por la atributo \"%s\". "
|
||||
"La bitrapido estas ŝanĝite al %d kBit/s."
|
||||
|
||||
msgid "Failed to configure TwoLAME encoder. Check your encoding parameters."
|
||||
msgstr "Fiaskis agordi la TwoLAME-kodilon. Kontrolu viajn kodad-parametrojn."
|
||||
|
||||
msgid "This stream contains no data."
|
||||
msgstr "Tiu fluo enhavas neniun datumon."
|
||||
|
||||
msgid "Internal data stream error."
|
||||
msgstr "Interna datum-flu-eraro."
|
Loading…
Reference in a new issue