mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 21:51:09 +00:00
Merge branch 'master' into 0.11
Conflicts: gst-libs/gst/audio/gstaudioencoder.c gst-libs/gst/pbutils/gstdiscoverer.c
This commit is contained in:
commit
e44dd9db8f
6 changed files with 303 additions and 14 deletions
|
@ -177,6 +177,8 @@ enum
|
|||
#define DEFAULT_LATENCY 0
|
||||
#define DEFAULT_TOLERANCE 0
|
||||
#define DEFAULT_PLC FALSE
|
||||
#define DEFAULT_DRAINABLE TRUE
|
||||
#define DEFAULT_NEEDS_FORMAT FALSE
|
||||
|
||||
typedef struct _GstAudioDecoderContext
|
||||
{
|
||||
|
@ -258,6 +260,8 @@ struct _GstAudioDecoderPrivate
|
|||
GstClockTime latency;
|
||||
GstClockTime tolerance;
|
||||
gboolean plc;
|
||||
gboolean drainable;
|
||||
gboolean needs_format;
|
||||
|
||||
/* pending serialized sink events, will be sent from finish_frame() */
|
||||
GList *pending_events;
|
||||
|
@ -420,6 +424,8 @@ gst_audio_decoder_init (GstAudioDecoder * dec, GstAudioDecoderClass * klass)
|
|||
dec->priv->latency = DEFAULT_LATENCY;
|
||||
dec->priv->tolerance = DEFAULT_TOLERANCE;
|
||||
dec->priv->plc = DEFAULT_PLC;
|
||||
dec->priv->drainable = DEFAULT_DRAINABLE;
|
||||
dec->priv->needs_format = DEFAULT_NEEDS_FORMAT;
|
||||
|
||||
/* init state */
|
||||
gst_audio_decoder_reset (dec, TRUE);
|
||||
|
@ -1049,6 +1055,7 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
|
|||
break;
|
||||
} else if (ret == GST_FLOW_OK) {
|
||||
GST_LOG_OBJECT (dec, "frame at offset %d of length %d", offset, len);
|
||||
g_assert (len);
|
||||
g_assert (offset + len <= av);
|
||||
priv->sync_flush = 0;
|
||||
} else {
|
||||
|
@ -1072,6 +1079,10 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force)
|
|||
} else {
|
||||
if (!force)
|
||||
break;
|
||||
if (!priv->drainable) {
|
||||
priv->drained = TRUE;
|
||||
break;
|
||||
}
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
|
@ -1392,6 +1403,9 @@ gst_audio_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
|||
|
||||
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,
|
||||
"received buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT
|
||||
", 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);
|
||||
|
||||
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)
|
||||
|
@ -2476,3 +2499,105 @@ gst_audio_decoder_get_tolerance (GstAudioDecoder * dec)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -296,6 +296,16 @@ void gst_audio_decoder_set_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
|
||||
|
||||
#endif /* _GST_AUDIO_DECODER_H_ */
|
||||
|
|
|
@ -180,6 +180,8 @@ enum
|
|||
#define DEFAULT_GRANULE FALSE
|
||||
#define DEFAULT_HARD_RESYNC FALSE
|
||||
#define DEFAULT_TOLERANCE 40000000
|
||||
#define DEFAULT_HARD_MIN FALSE
|
||||
#define DEFAULT_DRAINABLE TRUE
|
||||
|
||||
typedef struct _GstAudioEncoderContext
|
||||
{
|
||||
|
@ -239,6 +241,8 @@ struct _GstAudioEncoderPrivate
|
|||
gboolean perfect_ts;
|
||||
gboolean hard_resync;
|
||||
gboolean granule;
|
||||
gboolean hard_min;
|
||||
gboolean drainable;
|
||||
|
||||
/* pending tags */
|
||||
GstTagList *tags;
|
||||
|
@ -396,6 +400,8 @@ gst_audio_encoder_init (GstAudioEncoder * enc, GstAudioEncoderClass * bclass)
|
|||
enc->priv->perfect_ts = DEFAULT_PERFECT_TS;
|
||||
enc->priv->hard_resync = DEFAULT_HARD_RESYNC;
|
||||
enc->priv->tolerance = DEFAULT_TOLERANCE;
|
||||
enc->priv->hard_min = DEFAULT_HARD_MIN;
|
||||
enc->priv->drainable = DEFAULT_DRAINABLE;
|
||||
|
||||
/* init state */
|
||||
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;
|
||||
|
||||
data = gst_adapter_map (priv->adapter, priv->offset + need);
|
||||
buf =
|
||||
gst_buffer_new_wrapped_full ((gpointer) data, NULL, priv->offset,
|
||||
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",
|
||||
|
@ -786,14 +796,21 @@ gst_audio_encoder_push_buffers (GstAudioEncoder * enc, gboolean force)
|
|||
priv->offset += need;
|
||||
priv->samples_in += need / ctx->info.bpf;
|
||||
|
||||
priv->got_data = FALSE;
|
||||
ret = klass->handle_frame (enc, buf);
|
||||
/* subclass might not want to be bothered with leftover data,
|
||||
* 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)) {
|
||||
gst_buffer_unref (buf);
|
||||
gst_adapter_unmap (priv->adapter);
|
||||
}
|
||||
|
||||
finish:
|
||||
/* no data to feed, no leftover provided, then bail out */
|
||||
if (G_UNLIKELY (!buf && !priv->got_data)) {
|
||||
priv->drained = TRUE;
|
||||
|
@ -2135,6 +2152,106 @@ gst_audio_encoder_get_tolerance (GstAudioEncoder * enc)
|
|||
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:
|
||||
* @enc: a #GstAudioEncoder
|
||||
|
|
|
@ -250,6 +250,16 @@ void gst_audio_encoder_set_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,
|
||||
const GstTagList * tags, GstTagMergeMode mode);
|
||||
|
||||
|
|
|
@ -1024,6 +1024,31 @@ discoverer_collect (GstDiscoverer * dc)
|
|||
if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)) {
|
||||
GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (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) {
|
||||
|
|
|
@ -175,13 +175,15 @@
|
|||
* <refsect2>
|
||||
* <title>Specifying which CD/DVD device to use</title>
|
||||
* 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
|
||||
* is to connect to playbin's "notify::source" signal, which will be emitted
|
||||
* by playbin when it has created the source element for a particular URI.
|
||||
* In the signal callback you can check if the source element has a "device"
|
||||
* property and set it appropriately. In future ways might be added to specify
|
||||
* the device as part of the URI, but at the time of writing this is not
|
||||
* possible yet.
|
||||
* playbin creates before it is opened. The most generic way of doing this
|
||||
* is to connect to playbin's "source-setup" (or "notify::source") signal,
|
||||
* which will be emitted by playbin2 when it has created the source element
|
||||
* for a particular URI. In the signal callback you can check if the source
|
||||
* element has a "device" property and set it appropriately. In some cases
|
||||
* the device can also be set as part of the URI, but it depends on the
|
||||
* 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>
|
||||
* <title>Handling redirects</title>
|
||||
|
@ -196,19 +198,19 @@
|
|||
* <refsect2>
|
||||
* <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
|
||||
* audio decoders required to decode the content are installed. Since no
|
||||
* 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
|
||||
* 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
|
||||
* the drive is detected automatically by the plugin).
|
||||
* |[
|
||||
* gst-launch -v playbin uri=dvd://1
|
||||
* ]| This will play back title 1 of a DVD in your disc drive (assuming
|
||||
* gst-launch -v playbin2 uri=dvd://
|
||||
* ]| This will play back the DVD in your disc drive (assuming
|
||||
* the drive is detected automatically by the plugin).
|
||||
* </refsect2>
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue