Merge branch 'master' into 0.11

Conflicts:
	gst-libs/gst/audio/gstaudioencoder.c
	gst-libs/gst/pbutils/gstdiscoverer.c
This commit is contained in:
Wim Taymans 2012-02-16 14:23:28 +01:00
commit e44dd9db8f
6 changed files with 303 additions and 14 deletions

View file

@ -177,6 +177,8 @@ enum
#define DEFAULT_LATENCY 0 #define DEFAULT_LATENCY 0
#define DEFAULT_TOLERANCE 0 #define DEFAULT_TOLERANCE 0
#define DEFAULT_PLC FALSE #define DEFAULT_PLC FALSE
#define DEFAULT_DRAINABLE TRUE
#define DEFAULT_NEEDS_FORMAT FALSE
typedef struct _GstAudioDecoderContext typedef struct _GstAudioDecoderContext
{ {
@ -258,6 +260,8 @@ struct _GstAudioDecoderPrivate
GstClockTime latency; GstClockTime latency;
GstClockTime tolerance; GstClockTime tolerance;
gboolean plc; gboolean plc;
gboolean drainable;
gboolean needs_format;
/* pending serialized sink events, will be sent from finish_frame() */ /* pending serialized sink events, will be sent from finish_frame() */
GList *pending_events; GList *pending_events;
@ -420,6 +424,8 @@ gst_audio_decoder_init (GstAudioDecoder * dec, GstAudioDecoderClass * klass)
dec->priv->latency = DEFAULT_LATENCY; dec->priv->latency = DEFAULT_LATENCY;
dec->priv->tolerance = DEFAULT_TOLERANCE; dec->priv->tolerance = DEFAULT_TOLERANCE;
dec->priv->plc = DEFAULT_PLC; dec->priv->plc = DEFAULT_PLC;
dec->priv->drainable = DEFAULT_DRAINABLE;
dec->priv->needs_format = DEFAULT_NEEDS_FORMAT;
/* init state */ /* init state */
gst_audio_decoder_reset (dec, TRUE); gst_audio_decoder_reset (dec, TRUE);
@ -1049,6 +1055,7 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
break; break;
} else if (ret == GST_FLOW_OK) { } else if (ret == GST_FLOW_OK) {
GST_LOG_OBJECT (dec, "frame at offset %d of length %d", offset, len); GST_LOG_OBJECT (dec, "frame at offset %d of length %d", offset, len);
g_assert (len);
g_assert (offset + len <= av); g_assert (offset + len <= av);
priv->sync_flush = 0; priv->sync_flush = 0;
} else { } else {
@ -1072,6 +1079,10 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
} else { } else {
if (!force) if (!force)
break; break;
if (!priv->drainable) {
priv->drained = TRUE;
break;
}
buffer = NULL; buffer = NULL;
} }
@ -1392,6 +1403,9 @@ gst_audio_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
dec = GST_AUDIO_DECODER (parent); dec = GST_AUDIO_DECODER (parent);
if (G_UNLIKELY (!gst_pad_has_current_caps (pad) && dec->priv->needs_format))
goto not_negotiated;
GST_LOG_OBJECT (dec, GST_LOG_OBJECT (dec,
"received buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT "received buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buffer), ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buffer),
@ -1429,6 +1443,15 @@ gst_audio_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
GST_AUDIO_DECODER_STREAM_UNLOCK (dec); GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
return ret; return ret;
/* ERRORS */
not_negotiated:
{
GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
("decoder not initialized"));
gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED;
}
} }
/* perform upstream byte <-> time conversion (duration, seeking) /* perform upstream byte <-> time conversion (duration, seeking)
@ -2476,3 +2499,105 @@ gst_audio_decoder_get_tolerance (GstAudioDecoder * dec)
return result; return result;
} }
/**
* gst_audio_decoder_set_drainable:
* @enc: a #GstAudioDecoder
* @enabled: new state
*
* Configures decoder drain handling. If drainable, subclass might
* be handed a NULL buffer to have it return any leftover decoded data.
* Otherwise, it is not considered so capable and will only ever be passed
* real data.
*
* MT safe.
*
* Since: 0.10.36
*/
void
gst_audio_decoder_set_drainable (GstAudioDecoder * dec, gboolean enabled)
{
g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
GST_OBJECT_LOCK (dec);
dec->priv->drainable = enabled;
GST_OBJECT_UNLOCK (dec);
}
/**
* gst_audio_decoder_get_drainable:
* @enc: a #GstAudioDecoder
*
* Queries decoder drain handling.
*
* Returns: TRUE if drainable handling is enabled.
*
* MT safe.
*
* Since: 0.10.36
*/
gboolean
gst_audio_decoder_get_drainable (GstAudioDecoder * dec)
{
gboolean result;
g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
GST_OBJECT_LOCK (dec);
result = dec->priv->drainable;
GST_OBJECT_UNLOCK (dec);
return result;
}
/**
* gst_audio_decoder_set_needs_format:
* @enc: a #GstAudioDecoder
* @enabled: new state
*
* Configures decoder format needs. If enabled, subclass needs to be
* negotiated with format caps before it can process any data. It will then
* never be handed any data before it has been configured.
* Otherwise, it might be handed data without having been configured and
* is then expected being able to do so either by default
* or based on the input data.
*
* MT safe.
*
* Since: 0.10.36
*/
void
gst_audio_decoder_set_needs_format (GstAudioDecoder * dec, gboolean enabled)
{
g_return_if_fail (GST_IS_AUDIO_DECODER (dec));
GST_OBJECT_LOCK (dec);
dec->priv->needs_format = enabled;
GST_OBJECT_UNLOCK (dec);
}
/**
* gst_audio_decoder_get_needs_format:
* @enc: a #GstAudioDecoder
*
* Queries decoder required format handling.
*
* Returns: TRUE if required format handling is enabled.
*
* MT safe.
*
* Since: 0.10.36
*/
gboolean
gst_audio_decoder_get_needs_format (GstAudioDecoder * dec)
{
gboolean result;
g_return_val_if_fail (GST_IS_AUDIO_DECODER (dec), 0);
GST_OBJECT_LOCK (dec);
result = dec->priv->needs_format;
GST_OBJECT_UNLOCK (dec);
return result;
}

View file

@ -296,6 +296,16 @@ void gst_audio_decoder_set_tolerance (GstAudioDecoder * dec,
gint64 gst_audio_decoder_get_tolerance (GstAudioDecoder * dec); gint64 gst_audio_decoder_get_tolerance (GstAudioDecoder * dec);
void gst_audio_decoder_set_drainable (GstAudioDecoder * dec,
gboolean enabled);
gboolean gst_audio_decoder_get_drainable (GstAudioDecoder * dec);
void gst_audio_decoder_set_needs_format (GstAudioDecoder * dec,
gboolean enabled);
gboolean gst_audio_decoder_get_needs_format (GstAudioDecoder * dec);
G_END_DECLS G_END_DECLS
#endif /* _GST_AUDIO_DECODER_H_ */ #endif /* _GST_AUDIO_DECODER_H_ */

View file

@ -180,6 +180,8 @@ enum
#define DEFAULT_GRANULE FALSE #define DEFAULT_GRANULE FALSE
#define DEFAULT_HARD_RESYNC FALSE #define DEFAULT_HARD_RESYNC FALSE
#define DEFAULT_TOLERANCE 40000000 #define DEFAULT_TOLERANCE 40000000
#define DEFAULT_HARD_MIN FALSE
#define DEFAULT_DRAINABLE TRUE
typedef struct _GstAudioEncoderContext typedef struct _GstAudioEncoderContext
{ {
@ -239,6 +241,8 @@ struct _GstAudioEncoderPrivate
gboolean perfect_ts; gboolean perfect_ts;
gboolean hard_resync; gboolean hard_resync;
gboolean granule; gboolean granule;
gboolean hard_min;
gboolean drainable;
/* pending tags */ /* pending tags */
GstTagList *tags; GstTagList *tags;
@ -396,6 +400,8 @@ gst_audio_encoder_init (GstAudioEncoder * enc, GstAudioEncoderClass * bclass)
enc->priv->perfect_ts = DEFAULT_PERFECT_TS; enc->priv->perfect_ts = DEFAULT_PERFECT_TS;
enc->priv->hard_resync = DEFAULT_HARD_RESYNC; enc->priv->hard_resync = DEFAULT_HARD_RESYNC;
enc->priv->tolerance = DEFAULT_TOLERANCE; enc->priv->tolerance = DEFAULT_TOLERANCE;
enc->priv->hard_min = DEFAULT_HARD_MIN;
enc->priv->drainable = DEFAULT_DRAINABLE;
/* init state */ /* init state */
gst_audio_encoder_reset (enc, TRUE); gst_audio_encoder_reset (enc, TRUE);
@ -769,13 +775,17 @@ gst_audio_encoder_push_buffers (GstAudioEncoder * enc, gboolean force)
} }
} }
if (need) { priv->got_data = FALSE;
if (G_LIKELY (need)) {
const guint8 *data; const guint8 *data;
data = gst_adapter_map (priv->adapter, priv->offset + need); data = gst_adapter_map (priv->adapter, priv->offset + need);
buf = buf =
gst_buffer_new_wrapped_full ((gpointer) data, NULL, priv->offset, gst_buffer_new_wrapped_full ((gpointer) data, NULL, priv->offset,
need); need);
} else if (!priv->drainable) {
GST_DEBUG_OBJECT (enc, "non-drainable and no more data");
goto finish;
} }
GST_LOG_OBJECT (enc, "providing subclass with %d bytes at offset %d", GST_LOG_OBJECT (enc, "providing subclass with %d bytes at offset %d",
@ -786,14 +796,21 @@ gst_audio_encoder_push_buffers (GstAudioEncoder * enc, gboolean force)
priv->offset += need; priv->offset += need;
priv->samples_in += need / ctx->info.bpf; priv->samples_in += need / ctx->info.bpf;
priv->got_data = FALSE; /* subclass might not want to be bothered with leftover data,
ret = klass->handle_frame (enc, buf); * so take care of that here if so, otherwise pass along */
if (G_UNLIKELY (priv->force && priv->hard_min && buf)) {
GST_DEBUG_OBJECT (enc, "bypassing subclass with leftover");
ret = gst_audio_encoder_finish_frame (enc, NULL, -1);
} else {
ret = klass->handle_frame (enc, buf);
}
if (G_LIKELY (buf)) { if (G_LIKELY (buf)) {
gst_buffer_unref (buf); gst_buffer_unref (buf);
gst_adapter_unmap (priv->adapter); gst_adapter_unmap (priv->adapter);
} }
finish:
/* no data to feed, no leftover provided, then bail out */ /* no data to feed, no leftover provided, then bail out */
if (G_UNLIKELY (!buf && !priv->got_data)) { if (G_UNLIKELY (!buf && !priv->got_data)) {
priv->drained = TRUE; priv->drained = TRUE;
@ -2135,6 +2152,106 @@ gst_audio_encoder_get_tolerance (GstAudioEncoder * enc)
return result; return result;
} }
/**
* gst_audio_encoder_set_hard_min:
* @enc: a #GstAudioEncoder
* @enabled: new state
*
* Configures encoder hard minimum handling. If enabled, subclass
* will never be handed less samples than it configured, which otherwise
* might occur near end-of-data handling. Instead, the leftover samples
* will simply be discarded.
*
* MT safe.
*
* Since: 0.10.36
*/
void
gst_audio_encoder_set_hard_min (GstAudioEncoder * enc, gboolean enabled)
{
g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
GST_OBJECT_LOCK (enc);
enc->priv->hard_min = enabled;
GST_OBJECT_UNLOCK (enc);
}
/**
* gst_audio_encoder_get_hard_min:
* @enc: a #GstAudioEncoder
*
* Queries encoder hard minimum handling.
*
* Returns: TRUE if hard minimum handling is enabled.
*
* MT safe.
*
* Since: 0.10.36
*/
gboolean
gst_audio_encoder_get_hard_min (GstAudioEncoder * enc)
{
gboolean result;
g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
GST_OBJECT_LOCK (enc);
result = enc->priv->hard_min;
GST_OBJECT_UNLOCK (enc);
return result;
}
/**
* gst_audio_encoder_set_drainable:
* @enc: a #GstAudioEncoder
* @enabled: new state
*
* Configures encoder drain handling. If drainable, subclass might
* be handed a NULL buffer to have it return any leftover encoded data.
* Otherwise, it is not considered so capable and will only ever be passed
* real data.
*
* MT safe.
*
* Since: 0.10.36
*/
void
gst_audio_encoder_set_drainable (GstAudioEncoder * enc, gboolean enabled)
{
g_return_if_fail (GST_IS_AUDIO_ENCODER (enc));
GST_OBJECT_LOCK (enc);
enc->priv->drainable = enabled;
GST_OBJECT_UNLOCK (enc);
}
/**
* gst_audio_encoder_get_drainable:
* @enc: a #GstAudioEncoder
*
* Queries encoder drain handling.
*
* Returns: TRUE if drainable handling is enabled.
*
* MT safe.
*
* Since: 0.10.36
*/
gboolean
gst_audio_encoder_get_drainable (GstAudioEncoder * enc)
{
gboolean result;
g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);
GST_OBJECT_LOCK (enc);
result = enc->priv->drainable;
GST_OBJECT_UNLOCK (enc);
return result;
}
/** /**
* gst_audio_encoder_merge_tags: * gst_audio_encoder_merge_tags:
* @enc: a #GstAudioEncoder * @enc: a #GstAudioEncoder

View file

@ -250,6 +250,16 @@ void gst_audio_encoder_set_tolerance (GstAudioEncoder * enc,
gint64 gst_audio_encoder_get_tolerance (GstAudioEncoder * enc); gint64 gst_audio_encoder_get_tolerance (GstAudioEncoder * enc);
void gst_audio_encoder_set_hard_min (GstAudioEncoder * enc,
gboolean enabled);
gboolean gst_audio_encoder_get_hard_min (GstAudioEncoder * enc);
void gst_audio_encoder_set_drainable (GstAudioEncoder * enc,
gboolean enabled);
gboolean gst_audio_encoder_get_drainable (GstAudioEncoder * enc);
void gst_audio_encoder_merge_tags (GstAudioEncoder * enc, void gst_audio_encoder_merge_tags (GstAudioEncoder * enc,
const GstTagList * tags, GstTagMergeMode mode); const GstTagList * tags, GstTagMergeMode mode);

View file

@ -1024,6 +1024,31 @@ discoverer_collect (GstDiscoverer * dc)
if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)) { if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)) {
GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur)); GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
dc->priv->current_info->duration = (guint64) dur; dc->priv->current_info->duration = (guint64) dur;
} else {
GstStateChangeReturn sret;
/* Some parsers may not even return a rough estimate right away, e.g.
* because they've only processed a single frame so far, so if we
* didn't get a duration the first time, spin a bit and try again.
* Ugly, but still better than making parsers or other elements return
* completely bogus values. We need some API extensions to solve this
* better. */
GST_INFO ("No duration yet, try a bit harder..");
sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (sret != GST_STATE_CHANGE_FAILURE) {
int i;
for (i = 0; i < 2; ++i) {
g_usleep (G_USEC_PER_SEC / 20);
if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)
&& dur > 0) {
GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
dc->priv->current_info->duration = (guint64) dur;
break;
}
}
gst_element_set_state (pipeline, GST_STATE_PAUSED);
}
} }
if (dc->priv->seeking_query) { if (dc->priv->seeking_query) {

View file

@ -175,13 +175,15 @@
* <refsect2> * <refsect2>
* <title>Specifying which CD/DVD device to use</title> * <title>Specifying which CD/DVD device to use</title>
* The device to use for CDs/DVDs needs to be set on the source element * The device to use for CDs/DVDs needs to be set on the source element
* playbin creates before it is opened. The only way to do this at the moment * playbin creates before it is opened. The most generic way of doing this
* is to connect to playbin's "notify::source" signal, which will be emitted * is to connect to playbin's "source-setup" (or "notify::source") signal,
* by playbin when it has created the source element for a particular URI. * which will be emitted by playbin2 when it has created the source element
* In the signal callback you can check if the source element has a "device" * for a particular URI. In the signal callback you can check if the source
* property and set it appropriately. In future ways might be added to specify * element has a "device" property and set it appropriately. In some cases
* the device as part of the URI, but at the time of writing this is not * the device can also be set as part of the URI, but it depends on the
* possible yet. * elements involved if this will work or not. For example, for DVD menu
* playback, the following syntax might work (if the resindvd plugin is used):
* dvd://[/path/to/device]
* </refsect2> * </refsect2>
* <refsect2> * <refsect2>
* <title>Handling redirects</title> * <title>Handling redirects</title>
@ -196,19 +198,19 @@
* <refsect2> * <refsect2>
* <title>Examples</title> * <title>Examples</title>
* |[ * |[
* gst-launch -v playbin uri=file:///path/to/somefile.avi * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
* ]| This will play back the given AVI video file, given that the video and * ]| This will play back the given AVI video file, given that the video and
* audio decoders required to decode the content are installed. Since no * audio decoders required to decode the content are installed. Since no
* special audio sink or video sink is supplied (not possible via gst-launch), * special audio sink or video sink is supplied (not possible via gst-launch),
* playbin will try to find a suitable audio and video sink automatically * playbin will try to find a suitable audio and video sink automatically
* using the autoaudiosink and autovideosink elements. * using the autoaudiosink and autovideosink elements.
* |[ * |[
* gst-launch -v playbin uri=cdda://4 * gst-launch -v playbin2 uri=cdda://4
* ]| This will play back track 4 on an audio CD in your disc drive (assuming * ]| This will play back track 4 on an audio CD in your disc drive (assuming
* the drive is detected automatically by the plugin). * the drive is detected automatically by the plugin).
* |[ * |[
* gst-launch -v playbin uri=dvd://1 * gst-launch -v playbin2 uri=dvd://
* ]| This will play back title 1 of a DVD in your disc drive (assuming * ]| This will play back the DVD in your disc drive (assuming
* the drive is detected automatically by the plugin). * the drive is detected automatically by the plugin).
* </refsect2> * </refsect2>
*/ */