dtsdec: Reconcile element code with a52dec changes

Re-work the dtsdec element code to unify it with changes made it a52dec,
including support for reverse playback and dynamic channel negotiation
on the source pad.
This commit is contained in:
Jan Schmidt 2009-05-18 23:38:59 +01:00
parent 3fb997111f
commit b6e891bbda
2 changed files with 353 additions and 178 deletions

View file

@ -1,5 +1,6 @@
/* GStreamer DTS decoder plugin based on libdtsdec
* Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -84,43 +85,46 @@ typedef struct dts_state_s dca_state_t;
#include <liboil/liboilcpu.h>
#include <liboil/liboilfunction.h>
GST_DEBUG_CATEGORY_STATIC (dtsdec_debug);
#define GST_CAT_DEFAULT (dtsdec_debug)
static const GstElementDetails gst_dtsdec_details =
GST_ELEMENT_DETAILS ("DTS audio decoder",
"Codec/Decoder/Audio",
"Decodes DTS audio streams",
"Jan Schmidt <thaytan@noraisin.net>\n"
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
#if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED)
#define SAMPLE_WIDTH 16
#elif defined (LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE)
#define SAMPLE_WIDTH 64
#else
#define SAMPLE_WIDTH 32
#endif
GST_DEBUG_CATEGORY_STATIC (dtsdec_debug);
#define GST_CAT_DEFAULT (dtsdec_debug)
enum
{
ARG_0,
ARG_DRC
};
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-dts;" "audio/x-private1-dts")
GST_STATIC_CAPS ("audio/x-dts; audio/x-private1-dts")
);
#if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED)
#define DTS_CAPS "audio/x-raw-int, " \
"endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
"signed = (boolean) true, " \
"width = (int) 16, " \
"width = (int) " G_STRINGIFY (SAMPLE_WIDTH) ", " \
"depth = (int) 16"
#define SAMPLE_WIDTH 16
#elif defined(LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE)
#define DTS_CAPS "audio/x-raw-float, " \
"endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
"width = (int) 64"
#define SAMPLE_WIDTH 64
#else
#define DTS_CAPS "audio/x-raw-float, " \
"endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
"width = (int) 32"
#define SAMPLE_WIDTH 32
"width = (int) " G_STRINGIFY (SAMPLE_WIDTH)
#endif
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
@ -135,6 +139,7 @@ GST_BOILERPLATE (GstDtsDec, gst_dtsdec, GstElement, GST_TYPE_ELEMENT);
static gboolean gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_dtsdec_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstBuffer * buf);
static GstFlowReturn gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_dtsdec_change_state (GstElement * element,
GstStateChange transition);
@ -155,7 +160,7 @@ gst_dtsdec_base_init (gpointer g_class)
gst_static_pad_template_get (&src_factory));
gst_element_class_set_details (element_class, &gst_dtsdec_details);
GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS audio decoder");
GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS/DCA audio decoder");
}
static void
@ -202,6 +207,7 @@ gst_dtsdec_class_init (GstDtsDecClass * klass)
static void
gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class)
{
/* create the sink and src pads */
dtsdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_setcaps_function (dtsdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_dtsdec_sink_setcaps));
@ -212,10 +218,12 @@ gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class)
gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->sinkpad);
dtsdec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_use_fixed_caps (dtsdec->srcpad);
gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->srcpad);
dtsdec->request_channels = DCA_CHANNEL;
dtsdec->dynamic_range_compression = FALSE;
gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED);
}
static gint
@ -317,6 +325,105 @@ gst_dtsdec_channels (uint32_t flags, GstAudioChannelPosition ** pos)
return chans;
}
static void
clear_queued (GstDtsDec * dec)
{
g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
g_list_free (dec->queued);
dec->queued = NULL;
}
static GstFlowReturn
flush_queued (GstDtsDec * 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_dtsdec_drain (GstDtsDec * 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_dtsdec_push (GstDtsDec * dtsdec,
GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp)
{
GstBuffer *buf;
int chans, n, c;
GstFlowReturn result;
flags &= (DCA_CHANNEL_MASK | DCA_LFE);
chans = gst_dtsdec_channels (flags, NULL);
if (!chans) {
GST_ELEMENT_ERROR (GST_ELEMENT (dtsdec), STREAM, DECODE, (NULL),
("Invalid channel flags: %d", flags));
return GST_FLOW_ERROR;
}
result =
gst_pad_alloc_buffer_and_set_caps (srcpad, 0,
256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf);
if (result != GST_FLOW_OK)
return result;
for (n = 0; n < 256; n++) {
for (c = 0; c < chans; c++) {
((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] =
samples[c * 256 + n];
}
}
GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / dtsdec->sample_rate;
result = GST_FLOW_OK;
if ((buf = gst_audio_buffer_clip (buf, &dtsdec->segment,
dtsdec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) {
/* set discont when needed */
if (dtsdec->discont) {
GST_LOG_OBJECT (dtsdec, "marking DISCONT");
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
dtsdec->discont = FALSE;
}
if (dtsdec->segment.rate > 0.0) {
GST_DEBUG_OBJECT (dtsdec,
"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 (dtsdec, "queued frame");
dtsdec->queued = g_list_prepend (dtsdec->queued, buf);
}
}
return result;
}
static gboolean
gst_dtsdec_renegotiate (GstDtsDec * dts)
{
@ -360,32 +467,57 @@ gst_dtsdec_sink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:{
GstFormat format;
gint64 val;
gboolean update;
gint64 start, end, pos;
gdouble rate;
gst_event_parse_new_segment (event, NULL, NULL, &format, &val, NULL,
NULL);
if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (val)) {
GST_WARNING ("No time in newsegment event %p", event);
gst_event_parse_new_segment (event, &update, &rate, &format, &start, &end,
&pos);
/* drain queued buffers before activating the segment so that we can clip
* against the old segment first */
gst_dtsdec_drain (dtsdec);
if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) {
GST_WARNING ("No time in newsegment event %p (format is %s)",
event, gst_format_get_name (format));
gst_event_unref (event);
dtsdec->sent_segment = FALSE;
/* set some dummy values, FIXME: do proper conversion */
dtsdec->time = start = pos = 0;
format = GST_FORMAT_TIME;
end = -1;
} else {
dtsdec->current_ts = val;
dtsdec->time = start;
dtsdec->sent_segment = TRUE;
ret = gst_pad_push_event (dtsdec->srcpad, event);
}
if (dtsdec->cache) {
gst_buffer_unref (dtsdec->cache);
dtsdec->cache = NULL;
}
ret = gst_pad_event_default (pad, event);
gst_segment_set_newsegment (&dtsdec->segment, update, rate, format, start,
end, pos);
break;
}
case GST_EVENT_TAG:
ret = gst_pad_push_event (dtsdec->srcpad, event);
break;
case GST_EVENT_EOS:
gst_dtsdec_drain (dtsdec);
ret = gst_pad_push_event (dtsdec->srcpad, event);
break;
case GST_EVENT_FLUSH_START:
ret = gst_pad_push_event (dtsdec->srcpad, event);
break;
case GST_EVENT_FLUSH_STOP:
if (dtsdec->cache) {
gst_buffer_unref (dtsdec->cache);
dtsdec->cache = NULL;
}
ret = gst_pad_event_default (pad, event);
clear_queued (dtsdec);
gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED);
ret = gst_pad_push_event (dtsdec->srcpad, event);
break;
default:
ret = gst_pad_event_default (pad, event);
ret = gst_pad_push_event (dtsdec->srcpad, event);
break;
}
@ -393,24 +525,6 @@ gst_dtsdec_sink_event (GstPad * pad, GstEvent * event)
return ret;
}
static gboolean
gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad));
GstStructure *structure;
structure = gst_caps_get_structure (caps, 0);
if (structure && gst_structure_has_name (structure, "audio/x-private1-dts"))
dts->dvdmode = TRUE;
else
dts->dvdmode = FALSE;
gst_object_unref (dts);
return TRUE;
}
static void
gst_dtsdec_update_streaminfo (GstDtsDec * dts)
{
@ -419,6 +533,7 @@ gst_dtsdec_update_streaminfo (GstDtsDec * dts)
taglist = gst_tag_list_new ();
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
GST_TAG_AUDIO_CODEC, "DTS DCA",
GST_TAG_BITRATE, (guint) dts->bit_rate, NULL);
gst_element_found_tags_for_pad (GST_ELEMENT (dts), dts->srcpad, taglist);
@ -428,29 +543,37 @@ static GstFlowReturn
gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data,
guint length, gint flags, gint sample_rate, gint bit_rate)
{
gint channels, i, num_blocks;
gboolean need_renegotiation = FALSE;
gint channels, num_blocks;
GstBuffer *out;
gint i, s, c, num_c;
sample_t *samples;
GstFlowReturn result = GST_FLOW_OK;
/* go over stream properties, update caps/streaminfo if needed */
/* go over stream properties, renegotiate or update streaminfo if needed */
if (dts->sample_rate != sample_rate) {
need_renegotiation = TRUE;
dts->sample_rate = sample_rate;
}
dts->stream_channels = flags;
if (flags) {
dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
}
if (bit_rate != dts->bit_rate) {
dts->bit_rate = bit_rate;
gst_dtsdec_update_streaminfo (dts);
}
if (dts->request_channels == DCA_CHANNEL) {
/* 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
* downstream element such as audioconvert.
* FIXME: Add the property back in for forcing output channels.
*/
if (dts->request_channels != DCA_CHANNEL) {
flags = dts->request_channels;
} else if (dts->flag_update) {
GstCaps *caps;
dts->flag_update = FALSE;
caps = gst_pad_get_allowed_caps (dts->srcpad);
if (caps && gst_caps_get_size (caps) > 0) {
GstCaps *copy = gst_caps_copy_nth (caps, 0);
@ -472,38 +595,38 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data,
flags ? gst_dtsdec_channels (flags, NULL) : 6);
gst_structure_get_int (structure, "channels", &channels);
if (channels <= 6)
dts->request_channels = dts_channels[channels - 1];
flags = dts_channels[channels - 1];
else
dts->request_channels = dts_channels[5];
flags = dts_channels[5];
gst_caps_unref (copy);
} else if (flags) {
dts->request_channels = dts->stream_channels;
flags = dts->stream_channels;
} else {
dts->request_channels = DCA_3F2R | DCA_LFE;
flags = DCA_3F2R | DCA_LFE;
}
if (caps)
gst_caps_unref (caps);
} else {
flags = dts->using_channels;
}
/* process */
flags = dts->request_channels | DCA_ADJUST_LEVEL;
flags |= DCA_ADJUST_LEVEL;
dts->level = 1;
if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) {
GST_WARNING ("dts_frame error");
GST_WARNING_OBJECT (dts, "dts_frame error");
dts->discont = TRUE;
return GST_FLOW_OK;
}
channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
if (dts->using_channels != channels) {
need_renegotiation = TRUE;
dts->using_channels = channels;
}
if (need_renegotiation == TRUE) {
/* negotiate if required */
if (need_renegotiation) {
GST_DEBUG ("dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x",
dts->sample_rate, dts->stream_channels, dts->using_channels);
if (!gst_dtsdec_renegotiate (dts)) {
@ -520,107 +643,60 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data,
num_blocks = dca_blocks_num (dts->state);
for (i = 0; i < num_blocks; i++) {
if (dca_block (dts->state)) {
GST_WARNING ("dts_block error %d", i);
continue;
}
samples = dca_samples (dts->state);
num_c = gst_dtsdec_channels (dts->using_channels, NULL);
result = gst_pad_alloc_buffer_and_set_caps (dts->srcpad, 0,
(SAMPLE_WIDTH / 8) * 256 * num_c, GST_PAD_CAPS (dts->srcpad), &out);
if (result != GST_FLOW_OK)
break;
GST_BUFFER_TIMESTAMP (out) = dts->current_ts;
GST_BUFFER_DURATION (out) = GST_SECOND * 256 / dts->sample_rate;
dts->current_ts += GST_BUFFER_DURATION (out);
/* libdts returns buffers in 256-sample-blocks per channel,
* we want interleaved. And we need to copy anyway... */
data = GST_BUFFER_DATA (out);
for (s = 0; s < 256; s++) {
for (c = 0; c < num_c; c++) {
*(sample_t *) data = samples[s + c * 256];
data += (SAMPLE_WIDTH / 8);
}
}
/* push on */
result = gst_pad_push (dts->srcpad, out);
if (result != GST_FLOW_OK)
break;
}
return result;
}
static GstFlowReturn
gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf)
{
GstDtsDec *dts;
guint8 *data;
gint size;
gint length, flags, sample_rate, bit_rate, frame_length;
GstFlowReturn result = GST_FLOW_OK;
dts = GST_DTSDEC (GST_PAD_PARENT (pad));
if (dts->cache) {
buf = gst_buffer_join (dts->cache, buf);
dts->cache = NULL;
}
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
length = 0;
while (size >= 7) {
length = dca_syncinfo (dts->state, data, &flags,
&sample_rate, &bit_rate, &frame_length);
if (length == 0) {
/* shift window to re-find sync */
data++;
size--;
} else if (length <= size) {
GST_DEBUG ("Sync: frame size %d", length);
result = gst_dtsdec_handle_frame (dts, data, length,
flags, sample_rate, bit_rate);
if (result != GST_FLOW_OK) {
size = 0;
break;
}
size -= length;
data += length;
/* Ignore errors, but mark a discont */
GST_WARNING_OBJECT (dts, "dts_block error %d", i);
dts->discont = TRUE;
} else {
GST_LOG ("Not enough data available (needed %d had %d)", length, size);
break;
GstFlowReturn ret;
/* push on */
ret = gst_dtsdec_push (dts, dts->srcpad, dts->using_channels,
dts->samples, dts->time);
if (ret != GST_FLOW_OK)
return ret;
}
dts->time += GST_SECOND * 256 / dts->sample_rate;
}
/* keep cache */
if (length == 0) {
GST_LOG ("No sync found");
}
if (size > 0) {
dts->cache = gst_buffer_create_sub (buf,
GST_BUFFER_SIZE (buf) - size, size);
}
gst_buffer_unref (buf);
return result;
return GST_FLOW_OK;
}
static gboolean
gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad));
GstStructure *structure;
structure = gst_caps_get_structure (caps, 0);
if (structure && gst_structure_has_name (structure, "audio/x-private1-dts"))
dts->dvdmode = TRUE;
else
dts->dvdmode = FALSE;
gst_object_unref (dts);
return TRUE;
}
static GstFlowReturn
gst_dtsdec_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn res = GST_FLOW_OK;
GstFlowReturn ret = GST_FLOW_OK;
GstDtsDec *dts = GST_DTSDEC (GST_PAD_PARENT (pad));
gint first_access;
if (GST_BUFFER_IS_DISCONT (buf)) {
GST_LOG_OBJECT (dts, "received DISCONT");
gst_dtsdec_drain (dts);
/* clear cache on discont and mark a discont in the element */
if (dts->cache) {
gst_buffer_unref (dts->cache);
dts->cache = NULL;
}
dts->discont = TRUE;
}
if (dts->dvdmode) {
gint size = GST_BUFFER_SIZE (buf);
guint8 *data = GST_BUFFER_DATA (buf);
@ -644,8 +720,8 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf)
subbuf = gst_buffer_create_sub (buf, offset, len);
GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
res = gst_dtsdec_chain_raw (pad, subbuf);
if (res != GST_FLOW_OK)
ret = gst_dtsdec_chain_raw (pad, subbuf);
if (ret != GST_FLOW_OK)
goto done;
offset += len;
@ -655,21 +731,20 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf)
subbuf = gst_buffer_create_sub (buf, offset, len);
GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
res = gst_dtsdec_chain_raw (pad, subbuf);
ret = gst_dtsdec_chain_raw (pad, subbuf);
}
} else {
/* first_access = 0 or 1, so if there's a timestamp it applies
* to the first byte */
/* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
subbuf = gst_buffer_create_sub (buf, offset, size - offset);
GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
res = gst_dtsdec_chain_raw (pad, subbuf);
ret = gst_dtsdec_chain_raw (pad, subbuf);
}
} else {
res = gst_dtsdec_chain_raw (pad, buf);
ret = gst_dtsdec_chain_raw (pad, buf);
}
done:
return res;
return ret;
/* ERRORS */
not_enough_data:
@ -684,7 +759,97 @@ bad_first_access_parameter:
("Bad first_access parameter (%d) in buffer", first_access));
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf)
{
GstDtsDec *dts;
guint8 *data;
gint size;
gint length = 0, flags, sample_rate, bit_rate, frame_length;
GstFlowReturn result = GST_FLOW_OK;
dts = GST_DTSDEC (GST_PAD_PARENT (pad));
if (!dts->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 (dts->srcpad, gst_event_new_new_segment (FALSE,
segment.rate, segment.format, segment.start,
segment.duration, segment.start));
dts->sent_segment = TRUE;
}
/* merge with cache, if any. Also make sure timestamps match */
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
dts->time = GST_BUFFER_TIMESTAMP (buf);
GST_DEBUG_OBJECT (dts,
"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 (dts->cache) {
buf = gst_buffer_join (dts->cache, buf);
dts->cache = NULL;
}
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
/* find and read header */
bit_rate = dts->bit_rate;
sample_rate = dts->sample_rate;
flags = 0;
while (size >= 7) {
length = dca_syncinfo (dts->state, data, &flags,
&sample_rate, &bit_rate, &frame_length);
if (length == 0) {
/* shift window to re-find sync */
data++;
size--;
} else if (length <= size) {
GST_DEBUG ("Sync: frame size %d", length);
if (flags != dts->prev_flags)
dts->flag_update = TRUE;
dts->prev_flags = flags;
result = gst_dtsdec_handle_frame (dts, data, length,
flags, sample_rate, bit_rate);
if (result != GST_FLOW_OK) {
size = 0;
break;
}
size -= length;
data += length;
} else {
GST_LOG ("Not enough data available (needed %d had %d)", length, size);
break;
}
}
/* keep cache */
if (length == 0) {
GST_LOG ("No sync found");
}
if (size > 0) {
dts->cache = gst_buffer_create_sub (buf,
GST_BUFFER_SIZE (buf) - size, size);
}
gst_buffer_unref (buf);
return result;
}
static GstStateChangeReturn
@ -705,13 +870,14 @@ gst_dtsdec_change_state (GstElement * element, GstStateChange transition)
dts->samples = dca_samples (dts->state);
dts->bit_rate = -1;
dts->sample_rate = -1;
dts->stream_channels = 0;
/* FIXME force stereo for now */
dts->request_channels = DCA_CHANNEL;
dts->using_channels = 0;
dts->stream_channels = DCA_CHANNEL;
dts->using_channels = DCA_CHANNEL;
dts->level = 1;
dts->bias = 0;
dts->current_ts = 0;
dts->time = 0;
dts->sent_segment = FALSE;
dts->flag_update = TRUE;
gst_segment_init (&dts->segment, GST_FORMAT_UNDEFINED);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@ -730,6 +896,7 @@ gst_dtsdec_change_state (GstElement * element, GstStateChange transition)
gst_buffer_unref (dts->cache);
dts->cache = NULL;
}
clear_queued (dts);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
dca_free (dts->state);

View file

@ -43,15 +43,22 @@ struct _GstDtsDec {
GstElement element;
/* pads */
GstPad *sinkpad;
GstPad *srcpad;
GstPad *sinkpad;
GstPad *srcpad;
GstSegment segment;
gboolean dvdmode;
gboolean sent_segment;
gboolean discont;
gboolean flag_update;
gboolean prev_flags;
/* stream properties */
gint bit_rate;
gint sample_rate;
gint stream_channels;
gint request_channels;
gint using_channels;
gint bit_rate;
gint sample_rate;
gint stream_channels;
gint request_channels;
gint using_channels;
/* decoding properties */
sample_t level;
@ -63,13 +70,14 @@ struct _GstDtsDec {
#else
dts_state_t *state;
#endif
gboolean dvdmode;
/* Data left over from the previous buffer */
GstBuffer *cache;
/* keep track of time */
GstClockTime current_ts;
GstBuffer *cache;
GstClockTime time;
/* reverse playback */
GList *queued;
};
struct _GstDtsDecClass {