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:
Sebastian Dröge 2012-01-10 15:17:11 +01:00
commit 31063f0098
18 changed files with 820 additions and 465 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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;
};

View file

@ -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;

View file

@ -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

View file

@ -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) {

View file

@ -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 {

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -1 +1 @@
noinst_HEADERS = gst-i18n-plugin.h gettext.h
noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h

View 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

View file

@ -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>

View file

@ -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"

View file

@ -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);

View file

@ -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"

View file

@ -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
View 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."