Merge branch 'master' into 0.11

Conflicts:
	ext/cairo/gsttextoverlay.c
	ext/pulse/pulseaudiosink.c
	gst/audioparsers/gstaacparse.c
	gst/avi/gstavimux.c
	gst/flv/gstflvmux.c
	gst/interleave/interleave.c
	gst/isomp4/gstqtmux.c
	gst/matroska/matroska-demux.c
	gst/matroska/matroska-mux.c
	gst/matroska/matroska-mux.h
	gst/matroska/matroska-read-common.c
	gst/multifile/gstmultifilesink.c
	gst/multipart/multipartmux.c
	gst/shapewipe/gstshapewipe.c
	gst/smpte/gstsmpte.c
	gst/udp/gstmultiudpsink.c
	gst/videobox/gstvideobox.c
	gst/videocrop/gstaspectratiocrop.c
	gst/videomixer/videomixer.c
	gst/videomixer/videomixer2.c
	gst/wavparse/gstwavparse.c
	po/ja.po
	po/lv.po
	po/sr.po
	tests/check/Makefile.am
	tests/check/elements/qtmux.c
	tests/check/elements/rgvolume.c
This commit is contained in:
Sebastian Dröge 2012-01-10 14:32:32 +01:00
commit 93e3ed5a86
85 changed files with 2634 additions and 680 deletions

View file

@ -26,7 +26,8 @@ DISTCLEANFILES = _stdint.h
noinst_HEADERS = \
gst-libs/gst/gettext.h \
gst-libs/gst/gst-i18n-plugin.h
gst-libs/gst/gst-i18n-plugin.h \
gst-libs/gst/glib-compat-private.h
ACLOCAL_AMFLAGS = -I m4 -I common/m4

View file

@ -203,7 +203,7 @@ AC_CHECK_TYPE([struct ip_mreqn], [
dnl *** checks for dependency libraries ***
dnl GLib is required
AG_GST_GLIB_CHECK([2.20])
AG_GST_GLIB_CHECK([2.24])
PKG_CHECK_MODULES(GIO, [ gio-2.0 >= 2.20 ], , AC_MSG_ERROR([gio is required]))
dnl Orc
@ -438,6 +438,12 @@ int main ()
AC_SUBST(HAVE_DIRECTSOUND)
])
dnl *** Win32 WaveOut ***
translit(dnm, m, l) AM_CONDITIONAL(USE_WAVEFORM, true)
AG_GST_CHECK_FEATURE(WAVEFORM, [Win32 WaveForm], waveformsink, [
AC_CHECK_HEADER(mmsystem.h, HAVE_WAVEFORM="yes", HAVE_WAVEFORM="no", [#include <windows.h>])
])
dnl *** OSS audio *** (Linux, *BSD)
translit(dnm, m, l) AM_CONDITIONAL(USE_OSS, true)
AG_GST_CHECK_FEATURE(OSS, [OSS audio], ossaudio, [
@ -1005,6 +1011,7 @@ AM_CONDITIONAL(USE_SOUP, false)
AM_CONDITIONAL(USE_SPEEX, false)
AM_CONDITIONAL(USE_SUNAUDIO, false)
AM_CONDITIONAL(USE_TAGLIB, false)
AM_CONDITIONAL(USE_WAVEFORM, false)
AM_CONDITIONAL(USE_WAVPACK, false)
AM_CONDITIONAL(USE_X, false)
AM_CONDITIONAL(USE_XSHM, false)

View file

@ -106,7 +106,7 @@ static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
static GstPadLinkReturn gst_text_overlay_text_pad_linked (GstPad * pad,
GstPad * peer);
static void gst_text_overlay_text_pad_unlinked (GstPad * pad);
static GstFlowReturn gst_text_overlay_collected (GstCollectPads * pads,
static GstFlowReturn gst_text_overlay_collected (GstCollectPads2 * pads,
gpointer data);
static void gst_text_overlay_finalize (GObject * object);
static void gst_text_overlay_font_init (GstCairoTextOverlay * overlay);
@ -215,7 +215,7 @@ gst_text_overlay_finalize (GObject * object)
{
GstCairoTextOverlay *overlay = GST_CAIRO_TEXT_OVERLAY (object);
gst_collect_pads_stop (overlay->collect);
gst_collect_pads2_stop (overlay->collect);
gst_object_unref (overlay->collect);
g_free (overlay->text_fill_image);
@ -279,16 +279,16 @@ gst_text_overlay_init (GstCairoTextOverlay * overlay,
overlay->fps_n = 0;
overlay->fps_d = 1;
overlay->collect = gst_collect_pads_new ();
overlay->collect = gst_collect_pads2_new ();
gst_collect_pads_set_function (overlay->collect,
gst_collect_pads2_set_function (overlay->collect,
GST_DEBUG_FUNCPTR (gst_text_overlay_collected), overlay);
overlay->video_collect_data = gst_collect_pads_add_pad (overlay->collect,
overlay->video_sinkpad, sizeof (GstCollectData), NULL);
overlay->video_collect_data = gst_collect_pads2_add_pad (overlay->collect,
overlay->video_sinkpad, sizeof (GstCollectData2));
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* GstCollectPads2; because it sets its own event function giving the
* element no access to events. Nicked from avimux. */
overlay->collect_event =
(GstPadEventFunction) GST_PAD_EVENTFUNC (overlay->video_sinkpad);
@ -640,8 +640,8 @@ gst_text_overlay_text_pad_linked (GstPad * pad, GstPad * peer)
GST_DEBUG_OBJECT (overlay, "Text pad linked");
if (overlay->text_collect_data == NULL) {
overlay->text_collect_data = gst_collect_pads_add_pad (overlay->collect,
overlay->text_sinkpad, sizeof (GstCollectData), NULL);
overlay->text_collect_data = gst_collect_pads2_add_pad (overlay->collect,
overlay->text_sinkpad, sizeof (GstCollectData2));
}
overlay->need_render = TRUE;
@ -660,7 +660,7 @@ gst_text_overlay_text_pad_unlinked (GstPad * pad)
GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
if (overlay->text_collect_data) {
gst_collect_pads_remove_pad (overlay->collect, overlay->text_sinkpad);
gst_collect_pads2_remove_pad (overlay->collect, overlay->text_sinkpad);
overlay->text_collect_data = NULL;
}
@ -807,7 +807,7 @@ gst_text_overlay_pop_video (GstCairoTextOverlay * overlay)
{
GstBuffer *buf;
buf = gst_collect_pads_pop (overlay->collect, overlay->video_collect_data);
buf = gst_collect_pads2_pop (overlay->collect, overlay->video_collect_data);
g_return_if_fail (buf != NULL);
gst_buffer_unref (buf);
}
@ -818,7 +818,7 @@ gst_text_overlay_pop_text (GstCairoTextOverlay * overlay)
GstBuffer *buf;
if (overlay->text_collect_data) {
buf = gst_collect_pads_pop (overlay->collect, overlay->text_collect_data);
buf = gst_collect_pads2_pop (overlay->collect, overlay->text_collect_data);
g_return_if_fail (buf != NULL);
gst_buffer_unref (buf);
}
@ -828,7 +828,7 @@ gst_text_overlay_pop_text (GstCairoTextOverlay * overlay)
/* This function is called when there is data on all pads */
static GstFlowReturn
gst_text_overlay_collected (GstCollectPads * pads, gpointer data)
gst_text_overlay_collected (GstCollectPads2 * pads, gpointer data)
{
GstCairoTextOverlay *overlay;
GstFlowReturn ret = GST_FLOW_OK;
@ -842,14 +842,14 @@ gst_text_overlay_collected (GstCollectPads * pads, gpointer data)
GST_DEBUG ("Collecting");
video_frame = gst_collect_pads_peek (overlay->collect,
video_frame = gst_collect_pads2_peek (overlay->collect,
overlay->video_collect_data);
/* send EOS if video stream EOSed regardless of text stream */
if (video_frame == NULL) {
GST_DEBUG ("Video stream at EOS");
if (overlay->text_collect_data) {
text_buf = gst_collect_pads_pop (overlay->collect,
text_buf = gst_collect_pads2_pop (overlay->collect,
overlay->text_collect_data);
}
gst_pad_push_event (overlay->srcpad, gst_event_new_eos ());
@ -892,7 +892,7 @@ gst_text_overlay_collected (GstCollectPads * pads, gpointer data)
goto done;
}
text_buf = gst_collect_pads_peek (overlay->collect,
text_buf = gst_collect_pads2_peek (overlay->collect,
overlay->text_collect_data);
/* just push the video frame if the text stream has EOSed */
@ -1004,7 +1004,7 @@ gst_text_overlay_video_event (GstPad * pad, GstEvent * event)
gst_pad_push_event (overlay->srcpad, event);
}
/* now GstCollectPads can take care of the rest, e.g. EOS */
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
ret = overlay->collect_event (pad, event);
gst_object_unref (overlay);
return ret;
@ -1018,12 +1018,12 @@ gst_text_overlay_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_collect_pads_start (overlay->collect);
gst_collect_pads2_start (overlay->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* need to unblock the collectpads before calling the
* parent change_state so that streaming can finish */
gst_collect_pads_stop (overlay->collect);
gst_collect_pads2_stop (overlay->collect);
break;
default:
break;

View file

@ -3,7 +3,7 @@
#define __GST_CAIRO_TEXT_OVERLAY_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
G_BEGIN_DECLS
@ -45,9 +45,9 @@ struct _GstCairoTextOverlay {
GstPad *text_sinkpad;
GstPad *srcpad;
GstCollectPads *collect;
GstCollectData *video_collect_data;
GstCollectData *text_collect_data;
GstCollectPads2 *collect;
GstCollectData2 *video_collect_data;
GstCollectData2 *text_collect_data;
GstPadEventFunction collect_event;
gint width;

View file

@ -21,6 +21,11 @@
#ifdef HAVE_CONFIG_H
#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 <string.h>
#include <math.h>

View file

@ -41,6 +41,11 @@
#ifdef HAVE_CONFIG_H
#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 <string.h>
#include "gstflacdec.h"

View file

@ -271,7 +271,7 @@ gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
GST_INFO_OBJECT (sink, "format : %d", fmt);
GST_INFO_OBJECT (sink, "width x height : %d x %d", w, h);
GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_d, par_n);
GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_n, par_d);
return TRUE;
}
@ -344,7 +344,7 @@ gst_gdk_pixbuf_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf,
* The structure will take its own ref to the pixbuf. */
s = gst_structure_new (msg_name,
"pixbuf", GDK_TYPE_PIXBUF, pixbuf,
"pixel-aspect-ratio", GST_TYPE_FRACTION, sink->par_d, sink->par_n,
"pixel-aspect-ratio", GST_TYPE_FRACTION, sink->par_n, sink->par_d,
NULL);
msg = gst_message_new_element (GST_OBJECT_CAST (sink), s);

View file

@ -23,6 +23,8 @@
#include "gstjackaudioclient.h"
#include <gst/glib-compat-private.h>
GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug);
#define GST_CAT_DEFAULT gst_jack_audio_client_debug

View file

@ -329,7 +329,11 @@ gst_jack_ring_buffer_open_device (GstAudioRingBuffer * buf)
GST_DEBUG_OBJECT (sink, "open");
name = g_get_application_name ();
if (sink->client_name) {
name = sink->client_name;
} else {
name = g_get_application_name ();
}
if (!name)
name = "GStreamer";
@ -648,8 +652,9 @@ enum
SIGNAL_LAST
};
#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
#define DEFAULT_PROP_SERVER NULL
#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
#define DEFAULT_PROP_SERVER NULL
#define DEFAULT_PROP_CLIENT_NAME NULL
enum
{
@ -657,6 +662,7 @@ enum
PROP_CONNECT,
PROP_SERVER,
PROP_CLIENT,
PROP_CLIENT_NAME,
PROP_LAST
};
@ -705,6 +711,19 @@ gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass)
"The Jack server to connect to (NULL = default)",
DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstJackAudioSink:client-name
*
* The client name to use.
*
* Since: 0.10.31
*/
g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
g_param_spec_string ("client-name", "Client name",
"The client name of the Jack instance (NULL = default)",
DEFAULT_PROP_CLIENT_NAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT,
g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
GST_TYPE_JACK_CLIENT,
@ -738,6 +757,7 @@ gst_jack_audio_sink_init (GstJackAudioSink * sink)
sink->jclient = NULL;
sink->ports = NULL;
sink->port_count = 0;
sink->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
sink->buffers = NULL;
}
@ -747,6 +767,12 @@ gst_jack_audio_sink_dispose (GObject * object)
GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (object);
gst_caps_replace (&sink->caps, NULL);
if (sink->client_name != NULL) {
g_free (sink->client_name);
sink->client_name = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -759,6 +785,10 @@ gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
sink = GST_JACK_AUDIO_SINK (object);
switch (prop_id) {
case PROP_CLIENT_NAME:
g_free (sink->client_name);
sink->client_name = g_value_dup_string (value);
break;
case PROP_CONNECT:
sink->connect = g_value_get_enum (value);
break;
@ -787,6 +817,9 @@ gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
sink = GST_JACK_AUDIO_SINK (object);
switch (prop_id) {
case PROP_CLIENT_NAME:
g_value_set_string (value, sink->client_name);
break;
case PROP_CONNECT:
g_value_set_enum (value, sink->connect);
break;

View file

@ -58,6 +58,7 @@ struct _GstJackAudioSink {
GstJackConnect connect;
gchar *server;
jack_client_t *jclient;
gchar *client_name;
/* our client */
GstJackAudioClient *client;

View file

@ -336,7 +336,11 @@ gst_jack_ring_buffer_open_device (GstAudioRingBuffer * buf)
GST_DEBUG_OBJECT (src, "open");
name = g_get_application_name ();
if (src->client_name) {
name = src->client_name;
} else {
name = g_get_application_name ();
}
if (!name)
name = "GStreamer";
@ -651,8 +655,9 @@ enum
LAST_SIGNAL
};
#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
#define DEFAULT_PROP_SERVER NULL
#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
#define DEFAULT_PROP_SERVER NULL
#define DEFAULT_PROP_CLIENT_NAME NULL
enum
{
@ -660,6 +665,7 @@ enum
PROP_CONNECT,
PROP_SERVER,
PROP_CLIENT,
PROP_CLIENT_NAME,
PROP_LAST
};
@ -726,6 +732,19 @@ gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass)
"The Jack server to connect to (NULL = default)",
DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstJackAudioSrc:client-name
*
* The client name to use.
*
* Since: 0.10.31
*/
g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
g_param_spec_string ("client-name", "Client name",
"The client name of the Jack instance (NULL = default)",
DEFAULT_PROP_CLIENT_NAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT,
g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
GST_TYPE_JACK_CLIENT,
@ -765,6 +784,7 @@ gst_jack_audio_src_init (GstJackAudioSrc * src)
src->ports = NULL;
src->port_count = 0;
src->buffers = NULL;
src->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
}
static void
@ -773,6 +793,12 @@ gst_jack_audio_src_dispose (GObject * object)
GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
gst_caps_replace (&src->caps, NULL);
if (src->client_name != NULL) {
g_free (src->client_name);
src->client_name = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -783,6 +809,10 @@ gst_jack_audio_src_set_property (GObject * object, guint prop_id,
GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
switch (prop_id) {
case PROP_CLIENT_NAME:
g_free (src->client_name);
src->client_name = g_value_dup_string (value);
break;
case PROP_CONNECT:
src->connect = g_value_get_enum (value);
break;
@ -809,6 +839,9 @@ gst_jack_audio_src_get_property (GObject * object, guint prop_id,
GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
switch (prop_id) {
case PROP_CLIENT_NAME:
g_value_set_string (value, src->client_name);
break;
case PROP_CONNECT:
g_value_set_enum (value, src->connect);
break;

View file

@ -75,6 +75,7 @@ struct _GstJackAudioSrc
GstJackConnect connect;
gchar *server;
jack_client_t *jclient;
gchar *client_name;
/* our client */
GstJackAudioClient *client;

View file

@ -761,7 +761,7 @@ gst_jpeg_dec_getcaps (GstPad * pad, GstCaps * filter)
templ_caps = gst_pad_get_pad_template_caps (pad);
caps = gst_caps_intersect_full (peer_caps, templ_caps,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (peer_caps);
gst_object_unref (peer);
} else {
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));

View file

@ -58,6 +58,8 @@
#include <gst/pbutils/pbutils.h> /* only used for GST_PLUGINS_BASE_VERSION_* */
#include <gst/glib-compat-private.h>
#include "pulsesink.h"
#include "pulseutil.h"

View file

@ -42,6 +42,8 @@
#include <gst/base/gstbasesink.h>
#include "gstsouphttpclientsink.h"
#include <gst/glib-compat-private.h>
GST_DEBUG_CATEGORY_STATIC (souphttpclientsink_dbg);
#define GST_CAT_DEFAULT souphttpclientsink_dbg
@ -445,6 +447,20 @@ gst_soup_http_client_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
}
static gboolean
thread_ready_idle_cb (gpointer data)
{
GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (data);
GST_LOG_OBJECT (souphttpsink, "thread ready");
g_mutex_lock (souphttpsink->mutex);
g_cond_signal (souphttpsink->cond);
g_mutex_unlock (souphttpsink->mutex);
return FALSE; /* only run once */
}
static gpointer
thread_func (gpointer ptr)
{
@ -452,7 +468,6 @@ thread_func (gpointer ptr)
GST_DEBUG ("thread start");
souphttpsink->loop = g_main_loop_new (souphttpsink->context, TRUE);
g_main_loop_run (souphttpsink->loop);
GST_DEBUG ("thread quit");
@ -468,12 +483,35 @@ gst_soup_http_client_sink_start (GstBaseSink * sink)
if (souphttpsink->prop_session) {
souphttpsink->session = souphttpsink->prop_session;
} else {
GSource *source;
GError *error = NULL;
souphttpsink->context = g_main_context_new ();
/* set up idle source to signal when the main loop is running and
* it's safe for ::stop() to call g_main_loop_quit() */
source = g_idle_source_new ();
g_source_set_callback (source, thread_ready_idle_cb, sink, NULL);
g_source_attach (source, souphttpsink->context);
g_source_unref (source);
souphttpsink->loop = g_main_loop_new (souphttpsink->context, TRUE);
g_mutex_lock (souphttpsink->mutex);
/* FIXME: error handling */
#if !GLIB_CHECK_VERSION (2, 31, 0)
souphttpsink->thread = g_thread_create (thread_func, souphttpsink,
TRUE, &error);
#else
souphttpsink->thread = g_thread_try_new ("souphttpclientsink-thread",
thread_func, souphttpsink, &error);
#endif
GST_LOG_OBJECT (souphttpsink, "waiting for main loop thread to start up");
g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
g_mutex_unlock (souphttpsink->mutex);
GST_LOG_OBJECT (souphttpsink, "main loop thread running");
souphttpsink->session =
soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,

View file

@ -41,6 +41,11 @@
#ifdef HAVE_CONFIG_H
#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/gst.h>
#include <gst/gst-i18n-plugin.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

@ -145,6 +145,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
static GstStaticCaps gst_alpha_alpha_caps =
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }"));
/* FIXME: why do we need our own lock for this? */
#if !GLIB_CHECK_VERSION (2, 31, 0)
#define GST_ALPHA_LOCK(alpha) G_STMT_START { \
GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
g_static_mutex_lock (&alpha->lock); \
@ -155,6 +157,18 @@ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }"));
GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
g_static_mutex_unlock (&alpha->lock); \
} G_STMT_END
#else
#define GST_ALPHA_LOCK(alpha) G_STMT_START { \
GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
g_mutex_lock (&alpha->lock); \
GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
} G_STMT_END
#define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
g_mutex_unlock (&alpha->lock); \
} G_STMT_END
#endif
static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
@ -296,7 +310,11 @@ gst_alpha_init (GstAlpha * alpha)
alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
#if !GLIB_CHECK_VERSION (2, 31, 0)
g_static_mutex_init (&alpha->lock);
#else
g_mutex_init (&alpha->lock);
#endif
}
static void
@ -304,7 +322,11 @@ gst_alpha_finalize (GObject * object)
{
GstAlpha *alpha = GST_ALPHA (object);
#if !GLIB_CHECK_VERSION (2, 31, 0)
g_static_mutex_free (&alpha->lock);
#else
g_mutex_clear (&alpha->lock);
#endif
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View file

@ -69,7 +69,11 @@ struct _GstAlpha
/* <private> */
/* caps */
#if !GLIB_CHECK_VERSION (2, 31, 0)
GStaticMutex lock;
#else
GMutex lock;
#endif
gboolean in_sdtv, out_sdtv;

View file

@ -83,6 +83,8 @@
#include "audiochebband.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_audio_cheb_band_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -79,6 +79,8 @@
#include "audiocheblimit.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_audio_cheb_limit_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -56,6 +56,8 @@
#include "audiofirfilter.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_audio_fir_filter_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -52,6 +52,8 @@
#include "audioiirfilter.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_audio_iir_filter_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -63,6 +63,8 @@
#include "audiowsincband.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_gst_audio_wsincband_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -63,6 +63,8 @@
#include "audiowsinclimit.h"
#include "gst/glib-compat-private.h"
#define GST_CAT_DEFAULT gst_audio_wsinclimit_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

View file

@ -44,6 +44,7 @@
#include <string.h>
#include <gst/base/gstbitreader.h>
#include "gstaacparse.h"
@ -52,7 +53,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/mpeg, "
"framed = (boolean) true, " "mpegversion = (int) { 2, 4 }, "
"stream-format = (string) { raw, adts, adif };"));
"stream-format = (string) { raw, adts, adif, loas };"));
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@ -65,10 +66,21 @@ GST_DEBUG_CATEGORY_STATIC (aacparse_debug);
#define ADIF_MAX_SIZE 40 /* Should be enough */
#define ADTS_MAX_SIZE 10 /* Should be enough */
#define LOAS_MAX_SIZE 3 /* Should be enough */
#define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec)
static const gint loas_sample_rate_table[32] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
static const gint loas_channels_table[32] = {
0, 1, 2, 3, 4, 5, 6, 8,
0, 0, 0, 0, 0, 0, 0, 0
};
static gboolean gst_aac_parse_start (GstBaseParse * parse);
static gboolean gst_aac_parse_stop (GstBaseParse * parse);
@ -190,6 +202,9 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
case DSPAAC_HEADER_ADIF:
stream_format = "adif";
break;
case DSPAAC_HEADER_LOAS:
stream_format = "loas";
break;
default:
stream_format = NULL;
}
@ -329,6 +344,8 @@ gst_aac_parse_check_adts_frame (GstAacParse * aacparse,
const guint8 * data, const guint avail, gboolean drain,
guint * framesize, guint * needed_data)
{
*needed_data = 0;
if (G_UNLIKELY (avail < 2))
return FALSE;
@ -367,6 +384,292 @@ gst_aac_parse_check_adts_frame (GstAacParse * aacparse,
return FALSE;
}
static gboolean
gst_aac_parse_latm_get_value (GstAacParse * aacparse, GstBitReader * br,
guint32 * value)
{
guint8 bytes, i, byte;
*value = 0;
if (!gst_bit_reader_get_bits_uint8 (br, &bytes, 2))
return FALSE;
for (i = 0; i < bytes; ++i) {
*value <<= 8;
if (!gst_bit_reader_get_bits_uint8 (br, &byte, 8))
return FALSE;
*value += byte;
}
return TRUE;
}
static gboolean
gst_aac_parse_get_audio_object_type (GstAacParse * aacparse, GstBitReader * br,
guint8 * audio_object_type)
{
if (!gst_bit_reader_get_bits_uint8 (br, audio_object_type, 5))
return FALSE;
if (*audio_object_type == 31) {
if (!gst_bit_reader_get_bits_uint8 (br, audio_object_type, 6))
return FALSE;
*audio_object_type += 32;
}
GST_LOG_OBJECT (aacparse, "audio object type %u", *audio_object_type);
return TRUE;
}
static gboolean
gst_aac_parse_get_audio_sample_rate (GstAacParse * aacparse, GstBitReader * br,
gint * sample_rate)
{
guint8 sampling_frequency_index;
if (!gst_bit_reader_get_bits_uint8 (br, &sampling_frequency_index, 4))
return FALSE;
GST_LOG_OBJECT (aacparse, "sampling_frequency_index: %u",
sampling_frequency_index);
if (sampling_frequency_index == 0xf) {
guint32 sampling_rate;
if (!gst_bit_reader_get_bits_uint32 (br, &sampling_rate, 24))
return FALSE;
*sample_rate = sampling_rate;
} else {
*sample_rate = loas_sample_rate_table[sampling_frequency_index];
if (!*sample_rate)
return FALSE;
}
return TRUE;
}
/* See table 1.13 in ISO/IEC 14496-3 */
static gboolean
gst_aac_parse_read_loas_audio_specific_config (GstAacParse * aacparse,
GstBitReader * br, gint * sample_rate, gint * channels, guint32 * bits)
{
guint8 audio_object_type, channel_configuration;
if (!gst_aac_parse_get_audio_object_type (aacparse, br, &audio_object_type))
return FALSE;
if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (br, &channel_configuration, 4))
return FALSE;
GST_LOG_OBJECT (aacparse, "channel_configuration: %d", channel_configuration);
*channels = loas_channels_table[channel_configuration];
if (!*channels)
return FALSE;
if (audio_object_type == 5) {
GST_LOG_OBJECT (aacparse,
"Audio object type 5, so rereading sampling rate...");
if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
return FALSE;
}
GST_INFO_OBJECT (aacparse, "Found LOAS config: %d Hz, %d channels",
*sample_rate, *channels);
/* There's LOTS of stuff next, but we ignore it for now as we have
what we want (sample rate and number of channels */
GST_DEBUG_OBJECT (aacparse,
"Need more code to parse humongous LOAS data, currently ignored");
if (bits)
*bits = 0;
return TRUE;
}
static gboolean
gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
guint avail, gint * sample_rate, gint * channels, gint * version)
{
GstBitReader br;
guint8 u8, v, vA;
/* No version in the bitstream, but the spec has LOAS in the MPEG-4 section */
if (version)
*version = 4;
gst_bit_reader_init (&br, data, avail);
/* skip sync word (11 bits) and size (13 bits) */
gst_bit_reader_skip (&br, 11 + 13);
/* First bit is "use last config" */
if (!gst_bit_reader_get_bits_uint8 (&br, &u8, 1))
return FALSE;
if (u8) {
GST_DEBUG_OBJECT (aacparse, "Frame uses previous config");
if (!aacparse->sample_rate || !aacparse->channels) {
GST_WARNING_OBJECT (aacparse, "No previous config to use");
}
*sample_rate = aacparse->sample_rate;
*channels = aacparse->channels;
return TRUE;
}
GST_DEBUG_OBJECT (aacparse, "Frame contains new config");
if (!gst_bit_reader_get_bits_uint8 (&br, &v, 1))
return FALSE;
if (v) {
if (!gst_bit_reader_get_bits_uint8 (&br, &vA, 1))
return FALSE;
} else
vA = 0;
GST_LOG_OBJECT (aacparse, "v %d, vA %d", v, vA);
if (vA == 0) {
guint8 same_time, subframes, num_program, prog;
if (v == 1) {
guint32 value;
if (!gst_aac_parse_latm_get_value (aacparse, &br, &value))
return FALSE;
}
if (!gst_bit_reader_get_bits_uint8 (&br, &same_time, 1))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&br, &subframes, 6))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&br, &num_program, 4))
return FALSE;
GST_LOG_OBJECT (aacparse, "same_time %d, subframes %d, num_program %d",
same_time, subframes, num_program);
for (prog = 0; prog <= num_program; ++prog) {
guint8 num_layer, layer;
if (!gst_bit_reader_get_bits_uint8 (&br, &num_layer, 3))
return FALSE;
GST_LOG_OBJECT (aacparse, "Program %d: %d layers", prog, num_layer);
for (layer = 0; layer <= num_layer; ++layer) {
guint8 use_same_config;
if (prog == 0 && layer == 0) {
use_same_config = 0;
} else {
if (!gst_bit_reader_get_bits_uint8 (&br, &use_same_config, 1))
return FALSE;
}
if (!use_same_config) {
if (v == 0) {
if (!gst_aac_parse_read_loas_audio_specific_config (aacparse, &br,
sample_rate, channels, NULL))
return FALSE;
} else {
guint32 bits, asc_len;
if (!gst_aac_parse_latm_get_value (aacparse, &br, &asc_len))
return FALSE;
if (!gst_aac_parse_read_loas_audio_specific_config (aacparse, &br,
sample_rate, channels, &bits))
return FALSE;
asc_len -= bits;
gst_bit_reader_skip (&br, asc_len);
}
}
}
}
GST_WARNING_OBJECT (aacparse, "More data ignored");
} else {
GST_WARNING_OBJECT (aacparse, "Spec says \"TBD\"...");
}
return TRUE;
}
/**
* gst_aac_parse_loas_get_frame_len:
* @data: block of data containing a LOAS header.
*
* This function calculates LOAS frame length from the given header.
*
* Returns: size of the LOAS frame.
*/
static inline guint
gst_aac_parse_loas_get_frame_len (const guint8 * data)
{
return (((data[1] & 0x1f) << 8) | data[2]) + 3;
}
/**
* gst_aac_parse_check_loas_frame:
* @aacparse: #GstAacParse.
* @data: Data to be checked.
* @avail: Amount of data passed.
* @framesize: If valid LOAS frame was found, this will be set to tell the
* found frame size in bytes.
* @needed_data: If frame was not found, this may be set to tell how much
* more data is needed in the next round to detect the frame
* reliably. This may happen when a frame header candidate
* is found but it cannot be guaranteed to be the header without
* peeking the following data.
*
* Check if the given data contains contains LOAS frame. The algorithm
* will examine LOAS frame header and calculate the frame size. Also, another
* consecutive LOAS frame header need to be present after the found frame.
* Otherwise the data is not considered as a valid LOAS frame. However, this
* "extra check" is omitted when EOS has been received. In this case it is
* enough when data[0] contains a valid LOAS header.
*
* This function may set the #needed_data to indicate that a possible frame
* candidate has been found, but more data (#needed_data bytes) is needed to
* be absolutely sure. When this situation occurs, FALSE will be returned.
*
* When a valid frame is detected, this function will use
* gst_base_parse_set_min_frame_size() function from #GstBaseParse class
* to set the needed bytes for next frame.This way next data chunk is already
* of correct size.
*
* LOAS can have three different formats, if I read the spec correctly. Only
* one of them is supported here, as the two samples I have use this one.
*
* Returns: TRUE if the given data contains a valid LOAS header.
*/
static gboolean
gst_aac_parse_check_loas_frame (GstAacParse * aacparse,
const guint8 * data, const guint avail, gboolean drain,
guint * framesize, guint * needed_data)
{
*needed_data = 0;
/* 3 byte header */
if (G_UNLIKELY (avail < 3))
return FALSE;
if ((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) {
*framesize = gst_aac_parse_loas_get_frame_len (data);
GST_DEBUG_OBJECT (aacparse, "Found %u byte LOAS frame", *framesize);
/* In EOS mode this is enough. No need to examine the data further.
We also relax the check when we have sync, on the assumption that
if we're not looking at random data, we have a much higher chance
to get the correct sync, and this avoids losing two frames when
a single bit corruption happens. */
if (drain || !GST_BASE_PARSE_LOST_SYNC (aacparse)) {
return TRUE;
}
if (*framesize + LOAS_MAX_SIZE > avail) {
/* We have found a possible frame header candidate, but can't be
sure since we don't have enough data to check the next frame */
GST_DEBUG ("NEED MORE DATA: we need %d, available %d",
*framesize + LOAS_MAX_SIZE, avail);
*needed_data = *framesize + LOAS_MAX_SIZE;
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
*framesize + LOAS_MAX_SIZE);
return FALSE;
}
if ((data[*framesize] == 0x56) && ((data[*framesize + 1] & 0xe0) == 0xe0)) {
guint nextlen = gst_aac_parse_loas_get_frame_len (data + (*framesize));
GST_LOG ("LOAS frame found, len: %d bytes", *framesize);
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
nextlen + LOAS_MAX_SIZE);
return TRUE;
}
}
return FALSE;
}
/* caller ensure sufficient data */
static inline void
gst_aac_parse_parse_adts_header (GstAacParse * aacparse, const guint8 * data,
@ -412,7 +715,7 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
guint * framesize, gint * skipsize)
{
gboolean found = FALSE;
guint need_data = 0;
guint need_data_adts = 0, need_data_loas;
guint i = 0;
GST_DEBUG_OBJECT (aacparse, "Parsing header data");
@ -421,12 +724,16 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
stream */
/* Can we even parse the header? */
if (avail < ADTS_MAX_SIZE)
if (avail < MAX (ADTS_MAX_SIZE, LOAS_MAX_SIZE)) {
GST_DEBUG_OBJECT (aacparse, "Not enough data to check");
return FALSE;
}
for (i = 0; i < avail - 4; i++) {
if (((data[i] == 0xff) && ((data[i + 1] & 0xf6) == 0xf0)) ||
((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) ||
strncmp ((char *) data + i, "ADIF", 4) == 0) {
GST_DEBUG_OBJECT (aacparse, "Found ADIF signature at offset %u", i);
found = TRUE;
if (i) {
@ -446,7 +753,7 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
}
if (gst_aac_parse_check_adts_frame (aacparse, data, avail, drain,
framesize, &need_data)) {
framesize, &need_data_adts)) {
gint rate, channels;
GST_INFO ("ADTS ID: %d, framesize: %d", (data[1] & 0x08) >> 3, *framesize);
@ -464,7 +771,38 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE);
return TRUE;
} else if (need_data) {
}
if (gst_aac_parse_check_loas_frame (aacparse, data, avail, drain,
framesize, &need_data_loas)) {
gint rate, channels;
GST_INFO ("LOAS, framesize: %d", *framesize);
aacparse->header_type = DSPAAC_HEADER_LOAS;
if (!gst_aac_parse_read_loas_config (aacparse, data, avail, &rate,
&channels, &aacparse->mpegversion)) {
GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
return FALSE;
}
if (rate && channels) {
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), rate,
aacparse->frame_samples, 2, 2);
GST_DEBUG ("LOAS: samplerate %d, channels %d, objtype %d, version %d",
rate, channels, aacparse->object_type, aacparse->mpegversion);
aacparse->sample_rate = rate;
aacparse->channels = channels;
}
gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE);
return TRUE;
}
if (need_data_adts || need_data_loas) {
/* This tells the parent class not to skip any data */
*skipsize = 0;
return FALSE;
@ -612,6 +950,18 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse,
needed_data);
}
} else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
guint needed_data = 1024;
ret = gst_aac_parse_check_loas_frame (aacparse, data,
size, GST_BASE_PARSE_DRAINING (parse), framesize, &needed_data);
if (!ret) {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
needed_data);
}
} else {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
@ -632,7 +982,7 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse,
*
* Also determines frame overhead.
* ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have
* a per-frame header.
* a per-frame header. LOAS has 3 bytes.
*
* We're making a couple of simplifying assumptions:
*
@ -659,36 +1009,70 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
aacparse = GST_AAC_PARSE (parse);
buffer = frame->buffer;
if (G_UNLIKELY (aacparse->header_type != DSPAAC_HEADER_ADTS))
return ret;
if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
/* see above */
frame->overhead = 7;
/* see above */
frame->overhead = 7;
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
gst_aac_parse_parse_adts_header (aacparse, data,
&rate, &channels, NULL, NULL);
gst_buffer_unmap (buffer, data, size);
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
gst_aac_parse_parse_adts_header (aacparse, data,
&rate, &channels, NULL, NULL);
gst_buffer_unmap (buffer, data, size);
GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
if (G_UNLIKELY (rate != aacparse->sample_rate
|| channels != aacparse->channels)) {
GstCaps *sinkcaps;
if (G_UNLIKELY (rate != aacparse->sample_rate
|| channels != aacparse->channels)) {
GstCaps *sinkcaps;
aacparse->sample_rate = rate;
aacparse->channels = channels;
aacparse->sample_rate = rate;
aacparse->channels = channels;
sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
/* If linking fails, we need to return appropriate error */
sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
/* If linking fails, we need to return appropriate error */
ret = GST_FLOW_NOT_LINKED;
}
gst_caps_unref (sinkcaps);
ret = GST_FLOW_NOT_LINKED;
}
gst_caps_unref (sinkcaps);
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, aacparse->frame_samples, 2, 2);
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, aacparse->frame_samples, 2, 2);
}
} else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
gboolean setcaps = FALSE;
/* see above */
frame->overhead = 3;
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
if (!gst_aac_parse_read_loas_config (aacparse, data, size, &rate, &channels,
NULL)) {
GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
} else if (G_UNLIKELY (rate != aacparse->sample_rate
|| channels != aacparse->channels)) {
aacparse->sample_rate = rate;
aacparse->channels = channels;
setcaps = TRUE;
GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate,
channels);
}
gst_buffer_unmap (buffer, data, size);
/* We want to set caps both at start, and when rate/channels change.
Since only some LOAS frames have that info, we may receive frames
before knowing about rate/channels. */
if (setcaps
|| !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) {
GstCaps *sinkcaps =
gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
/* If linking fails, we need to return appropriate error */
ret = GST_FLOW_NOT_LINKED;
}
gst_caps_unref (sinkcaps);
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, aacparse->frame_samples, 2, 2);
}
}
return ret;

View file

@ -45,6 +45,7 @@ G_BEGIN_DECLS
* @DSPAAC_HEADER_UNKNOWN: Unknown (not recognized) header.
* @DSPAAC_HEADER_ADIF: ADIF header found.
* @DSPAAC_HEADER_ADTS: ADTS header found.
* @DSPAAC_HEADER_LOAS: LOAS header found.
* @DSPAAC_HEADER_NONE: Raw stream, no header.
*
* Type header enumeration set in #header_type.
@ -54,6 +55,7 @@ typedef enum {
DSPAAC_HEADER_UNKNOWN,
DSPAAC_HEADER_ADIF,
DSPAAC_HEADER_ADTS,
DSPAAC_HEADER_LOAS,
DSPAAC_HEADER_NONE
} GstAacHeaderType;

View file

@ -324,7 +324,9 @@ gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
/* spec not quite clear here: decoder should decode if less than 8,
* but seemingly only defines 6 and 8 cases */
if (bsid > 8) {
/* Files with 9 and 10 happen, and seem to comply with the <= 8
format, so let them through. The spec says nothing about 9 and 10 */
if (bsid > 10) {
GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid);
goto cleanup;
} else if (bsid != 8 && bsid != 6) {

View file

@ -45,6 +45,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 <string.h>
#include <stdio.h>

View file

@ -190,10 +190,10 @@ static GstStaticPadTemplate audio_sink_factory =
static void gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free);
static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads * pads,
static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads2 * pads,
GstAviMux * avimux);
static gboolean gst_avi_mux_handle_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean gst_avi_mux_handle_event (GstCollectPads2 * pad,
GstCollectData2 * data, GstEvent * event, gpointer user_data);
static GstPad *gst_avi_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_avi_mux_release_pad (GstElement * element, GstPad * pad);
@ -378,10 +378,13 @@ gst_avi_mux_init (GstAviMux * avimux)
/* property */
avimux->enable_large_avi = DEFAULT_BIGFILE;
avimux->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (avimux->collect,
(GstCollectPadsFunction) (GST_DEBUG_FUNCPTR (gst_avi_mux_collect_pads)),
avimux->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_function (avimux->collect,
(GstCollectPads2Function) (GST_DEBUG_FUNCPTR (gst_avi_mux_collect_pads)),
avimux);
gst_collect_pads2_set_event_function (avimux->collect,
(GstCollectPads2EventFunction) (GST_DEBUG_FUNCPTR
(gst_avi_mux_handle_event)), avimux);
/* set to clean state */
gst_avi_mux_reset (avimux);
@ -977,15 +980,9 @@ gst_avi_mux_request_new_pad (GstElement * element,
g_free (name);
avipad->collect = gst_collect_pads_add_pad (avimux->collect,
newpad, sizeof (GstAviCollectData), NULL);
avipad->collect = gst_collect_pads2_add_pad (avimux->collect,
newpad, sizeof (GstAviCollectData));
((GstAviCollectData *) (avipad->collect))->avipad = avipad;
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* element no access to events */
avimux->collect_event = GST_PAD_EVENTFUNC (newpad);
gst_pad_set_event_function (newpad,
GST_DEBUG_FUNCPTR (gst_avi_mux_handle_event));
if (!gst_element_add_pad (element, newpad))
goto pad_add_failed;
@ -1038,7 +1035,7 @@ gst_avi_mux_release_pad (GstElement * element, GstPad * pad)
* as it also represent number of streams present */
avipad->collect = NULL;
GST_DEBUG_OBJECT (avimux, "removed pad '%s'", GST_PAD_NAME (pad));
gst_collect_pads_remove_pad (avimux->collect, pad);
gst_collect_pads2_remove_pad (avimux->collect, pad);
gst_element_remove_pad (element, pad);
/* if not started yet, we can remove any sign this pad ever existed */
/* in this case _start will take care of the real pad count */
@ -1833,12 +1830,13 @@ gst_avi_mux_restart_file (GstAviMux * avimux)
/* handle events (search) */
static gboolean
gst_avi_mux_handle_event (GstPad * pad, GstObject * parent, GstEvent * event)
gst_avi_mux_handle_event (GstCollectPads2 * pads, GstCollectData2 * data,
GstEvent * event, gpointer user_data)
{
GstAviMux *avimux;
gboolean ret = TRUE;
gboolean ret = FALSE;
avimux = GST_AVI_MUX (parent);
avimux = GST_AVI_MUX (user_data);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
@ -1850,15 +1848,15 @@ gst_avi_mux_handle_event (GstPad * pad, GstObject * parent, GstEvent * event)
gst_event_parse_caps (event, &caps);
/* find stream data */
collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
collect_pad = (GstAviCollectData *) data;
g_assert (collect_pad);
avipad = (GstAviVideoPad *) collect_pad->avipad;
g_assert (avipad);
if (avipad->parent.is_video) {
ret = gst_avi_mux_vidsink_set_caps (pad, caps);
ret = gst_avi_mux_vidsink_set_caps (GST_PAD (avipad), caps);
} else {
ret = gst_avi_mux_audsink_set_caps (pad, caps);
ret = gst_avi_mux_audsink_set_caps (GST_PAD (avipad), caps);
}
break;
}
@ -1875,10 +1873,7 @@ gst_avi_mux_handle_event (GstPad * pad, GstObject * parent, GstEvent * event)
break;
}
/* now GstCollectPads can take care of the rest, e.g. EOS */
if (ret)
ret = avimux->collect_event (pad, parent, event);
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
return ret;
}
@ -1909,7 +1904,7 @@ gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
guint flags;
gsize datasize;
data = gst_collect_pads_pop (avimux->collect, avipad->collect);
data = gst_collect_pads2_pop (avimux->collect, avipad->collect);
/* arrange downstream running time */
data = gst_buffer_make_writable (data);
GST_BUFFER_TIMESTAMP (data) =
@ -2033,7 +2028,7 @@ gst_avi_mux_do_one_buffer (GstAviMux * avimux)
if (!avipad->hdr.fcc_handler)
goto not_negotiated;
buffer = gst_collect_pads_peek (avimux->collect, avipad->collect);
buffer = gst_collect_pads2_peek (avimux->collect, avipad->collect);
if (!buffer)
continue;
time = GST_BUFFER_TIMESTAMP (buffer);
@ -2046,7 +2041,7 @@ gst_avi_mux_do_one_buffer (GstAviMux * avimux)
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
GST_DEBUG_OBJECT (avimux, "clipping buffer on pad %s outside segment",
GST_PAD_NAME (avipad->collect->pad));
buffer = gst_collect_pads_pop (avimux->collect, avipad->collect);
buffer = gst_collect_pads2_pop (avimux->collect, avipad->collect);
gst_buffer_unref (buffer);
return GST_FLOW_OK;
}
@ -2085,7 +2080,7 @@ not_negotiated:
}
static GstFlowReturn
gst_avi_mux_collect_pads (GstCollectPads * pads, GstAviMux * avimux)
gst_avi_mux_collect_pads (GstCollectPads2 * pads, GstAviMux * avimux)
{
GstFlowReturn res;
@ -2144,12 +2139,12 @@ gst_avi_mux_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_collect_pads_start (avimux->collect);
gst_collect_pads2_start (avimux->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_collect_pads_stop (avimux->collect);
gst_collect_pads2_stop (avimux->collect);
break;
default:
break;

View file

@ -23,7 +23,7 @@
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
#include <gst/riff/riff-ids.h>
#include "avi-ids.h"
@ -74,7 +74,7 @@ typedef GstFlowReturn (*GstAviPadHook) (GstAviMux * avi, GstAviPad * avipad,
struct _GstAviPad {
/* do not extend, link to it */
/* is NULL if original sink request pad has been removed */
GstCollectData *collect;
GstCollectData2 *collect;
/* type */
gboolean is_video;
@ -129,7 +129,7 @@ typedef struct _GstAviAudioPad {
typedef struct _GstAviCollectData {
/* extend the CollectData */
GstCollectData collect;
GstCollectData2 collect;
GstAviPad *avipad;
} GstAviCollectData;
@ -143,8 +143,7 @@ struct _GstAviMux {
GSList *sinkpads;
/* video restricted to 1 pad */
guint video_pads, audio_pads;
GstCollectPads *collect;
GstPadEventFunction collect_event;
GstCollectPads2 *collect;
/* the AVI header */
/* still some single stream video data in mux struct */

View file

@ -32,6 +32,8 @@
#include "gstiirequalizer3bands.h"
#include "gstiirequalizer10bands.h"
#include "gst/glib-compat-private.h"
GST_DEBUG_CATEGORY (equalizer_debug);
#define GST_CAT_DEFAULT equalizer_debug

View file

@ -34,6 +34,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 "gstflvdemux.h"
#include "gstflvmux.h"

View file

@ -89,7 +89,11 @@ G_DEFINE_TYPE_WITH_CODE (GstFlvMux, gst_flv_mux, GST_TYPE_ELEMENT,
static void gst_flv_mux_finalize (GObject * object);
static GstFlowReturn
gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data);
gst_flv_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
GstBuffer * buf, gpointer user_data);
static gboolean
gst_flv_mux_handle_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
GstEvent * event, gpointer user_data);
static gboolean gst_flv_mux_handle_src_event (GstPad * pad, GstObject * parent,
GstEvent * event);
@ -209,9 +213,13 @@ gst_flv_mux_init (GstFlvMux * mux)
mux->new_tags = FALSE;
mux->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (mux->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_flv_mux_collected), mux);
mux->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_buffer_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_flv_mux_handle_buffer), mux);
gst_collect_pads2_set_event_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_flv_mux_handle_sink_event), mux);
gst_collect_pads2_set_clip_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_collect_pads2_clip_running_time), mux);
gst_flv_mux_reset (GST_ELEMENT (mux));
}
@ -273,11 +281,11 @@ gst_flv_mux_handle_src_event (GstPad * pad, GstObject * parent,
}
static gboolean
gst_flv_mux_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
gst_flv_mux_handle_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
GstEvent * event, gpointer user_data)
{
GstFlvMux *mux = GST_FLV_MUX (parent);
gboolean ret = TRUE;
GstFlvMux *mux = GST_FLV_MUX (user_data);
gboolean ret = FALSE;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
@ -288,13 +296,13 @@ gst_flv_mux_handle_sink_event (GstPad * pad, GstObject * parent,
gst_event_parse_caps (event, &caps);
/* find stream data */
flvpad = (GstFlvPad *) gst_pad_get_element_private (pad);
flvpad = (GstFlvPad *) data;
g_assert (flvpad);
if (flvpad->video) {
ret = gst_flv_mux_video_pad_setcaps (pad, caps);
ret = gst_flv_mux_video_pad_setcaps (data->pad, caps);
} else {
ret = gst_flv_mux_audio_pad_setcaps (pad, caps);
ret = gst_flv_mux_audio_pad_setcaps (data->pad, caps);
}
/* and eat */
ret = FALSE;
@ -315,10 +323,7 @@ gst_flv_mux_handle_sink_event (GstPad * pad, GstObject * parent,
break;
}
/* now GstCollectPads can take care of the rest, e.g. EOS */
if (ret)
ret = mux->collect_event (pad, parent, event);
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
return ret;
}
@ -567,20 +572,12 @@ gst_flv_mux_request_new_pad (GstElement * element,
pad = gst_pad_new_from_template (templ, name);
cpad = (GstFlvPad *)
gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstFlvPad), NULL);
gst_collect_pads2_add_pad (mux->collect, pad, sizeof (GstFlvPad));
cpad->audio_codec_data = NULL;
cpad->video_codec_data = NULL;
gst_flv_mux_reset_pad (mux, cpad, video);
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* element no access to events.
*/
mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
gst_pad_set_event_function (pad,
GST_DEBUG_FUNCPTR (gst_flv_mux_handle_sink_event));
gst_pad_set_active (pad, TRUE);
gst_element_add_pad (element, pad);
@ -594,7 +591,7 @@ gst_flv_mux_release_pad (GstElement * element, GstPad * pad)
GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad);
gst_flv_mux_reset_pad (mux, cpad, cpad->video);
gst_collect_pads_remove_pad (mux->collect, pad);
gst_collect_pads2_remove_pad (mux->collect, pad);
gst_element_remove_pad (element, pad);
}
@ -677,7 +674,7 @@ gst_flv_mux_create_number_script_value (const gchar * name, gdouble value)
}
static GstBuffer *
gst_flv_mux_create_metadata (GstFlvMux * mux)
gst_flv_mux_create_metadata (GstFlvMux * mux, gboolean full)
{
const GstTagList *tags;
GstBuffer *script_tag, *tmp;
@ -719,6 +716,9 @@ gst_flv_mux_create_metadata (GstFlvMux * mux)
GST_WRITE_UINT32_BE (data + 1, n_tags);
script_tag = gst_buffer_join (script_tag, tmp);
if (!full)
goto tags;
/* Some players expect the 'duration' to be always set. Fill it out later,
after querying the pads or after getting EOS */
if (!mux->streamable) {
@ -739,6 +739,7 @@ gst_flv_mux_create_metadata (GstFlvMux * mux)
GST_DEBUG_OBJECT (mux, "not preallocating index, streamable mode");
}
tags:
for (i = 0; tags && i < n_tags; i++) {
const gchar *tag_name =
gst_structure_nth_field_name ((const GstStructure *) tags, i);
@ -777,12 +778,15 @@ gst_flv_mux_create_metadata (GstFlvMux * mux)
}
}
if (!full)
goto end;
if (mux->duration == GST_CLOCK_TIME_NONE) {
GSList *l;
guint64 dur;
for (l = mux->collect->data; l; l = l->next) {
GstCollectData *cdata = l->data;
GstCollectData2 *cdata = l->data;
if (gst_pad_peer_query_duration (cdata->pad, GST_FORMAT_TIME,
(gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) {
@ -958,6 +962,14 @@ gst_flv_mux_create_metadata (GstFlvMux * mux)
tags_written++;
}
end:
if (!tags_written) {
gst_buffer_unref (script_tag);
script_tag = NULL;
goto exit;
}
_gst_buffer_new_and_alloc (2 + 0 + 1, &tmp, &data);
data[0] = 0; /* 0 byte size */
data[1] = 0;
@ -977,6 +989,7 @@ gst_flv_mux_create_metadata (GstFlvMux * mux)
GST_WRITE_UINT32_BE (data + 11 + 13 + 1, tags_written);
gst_buffer_unmap (script_tag, data, -1);
exit:
return script_tag;
}
@ -1125,7 +1138,7 @@ gst_flv_mux_write_header (GstFlvMux * mux)
GstFlowReturn ret;
header = gst_flv_mux_create_header (mux);
metadata = gst_flv_mux_create_metadata (mux);
metadata = gst_flv_mux_create_metadata (mux, TRUE);
video_codec_data = NULL;
audio_codec_data = NULL;
@ -1228,18 +1241,12 @@ gst_flv_mux_update_index (GstFlvMux * mux, GstBuffer * buffer, GstFlvPad * cpad)
}
static GstFlowReturn
gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvPad * cpad)
gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvPad * cpad, GstBuffer * buffer)
{
GstBuffer *tag;
GstBuffer *buffer =
gst_collect_pads_pop (mux->collect, (GstCollectData *) cpad);
GstFlowReturn ret;
/* arrange downstream running time */
buffer = gst_buffer_make_writable (buffer);
GST_BUFFER_TIMESTAMP (buffer) =
gst_segment_to_running_time (&cpad->collect.segment,
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer));
/* clipping function arranged for running_time */
if (!mux->streamable)
gst_flv_mux_update_index (mux, buffer, cpad);
@ -1276,12 +1283,6 @@ gst_flv_mux_determine_duration (GstFlvMux * mux)
}
}
if (duration == GST_CLOCK_TIME_NONE) {
GST_DEBUG_OBJECT (mux, "not able to determine duration "
"from pad timestamps, assuming 0");
return 0;
}
return duration;
}
@ -1296,6 +1297,7 @@ gst_flv_mux_rewrite_header (GstFlvMux * mux)
guint32 index_len, allocate_size;
guint32 i, index_skip;
GstSegment segment;
GstClockTime dur;
if (mux->streamable)
return GST_FLOW_OK;
@ -1309,9 +1311,12 @@ gst_flv_mux_rewrite_header (GstFlvMux * mux)
return GST_FLOW_OK;
}
/* if we were not able to determine the duration before, set it now */
if (mux->duration == GST_CLOCK_TIME_NONE)
mux->duration = gst_flv_mux_determine_duration (mux);
/* determine duration now based on our own timestamping,
* so that it is likely many times better and consistent
* than whatever obtained by some query */
dur = gst_flv_mux_determine_duration (mux);
if (dur != GST_CLOCK_TIME_NONE)
mux->duration = dur;
/* rewrite the duration tag */
d = gst_guint64_to_gdouble (mux->duration);
@ -1420,14 +1425,13 @@ gst_flv_mux_rewrite_header (GstFlvMux * mux)
}
static GstFlowReturn
gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data)
gst_flv_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
GstBuffer * buffer, gpointer user_data)
{
GstFlvMux *mux = GST_FLV_MUX (user_data);
GstFlvPad *best;
GstClockTime best_time;
GstFlowReturn ret;
GSList *sl;
gboolean eos = TRUE;
if (mux->state == GST_FLV_MUX_STATE_HEADER) {
GstSegment segment;
@ -1450,51 +1454,18 @@ gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data)
}
if (mux->new_tags) {
GstBuffer *buf = gst_flv_mux_create_metadata (mux);
gst_flv_mux_push (mux, buf);
GstBuffer *buf = gst_flv_mux_create_metadata (mux, FALSE);
if (buf)
gst_flv_mux_push (mux, buf);
mux->new_tags = FALSE;
}
best = NULL;
best_time = GST_CLOCK_TIME_NONE;
for (sl = mux->collect->data; sl; sl = sl->next) {
GstFlvPad *cpad = sl->data;
GstBuffer *buffer = gst_collect_pads_peek (pads, (GstCollectData *) cpad);
GstClockTime time;
if (!buffer)
continue;
eos = FALSE;
time = GST_BUFFER_TIMESTAMP (buffer);
gst_buffer_unref (buffer);
/* Use buffers without valid timestamp first */
if (!GST_CLOCK_TIME_IS_VALID (time)) {
GST_WARNING_OBJECT (pads, "Buffer without valid timestamp");
best_time = cpad->last_timestamp;
best = cpad;
break;
}
time = gst_segment_to_running_time (&cpad->collect.segment,
GST_FORMAT_TIME, time);
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
GST_PAD_NAME (cpad->collect.pad));
buffer = gst_collect_pads_pop (pads, (GstCollectData *) cpad);
gst_buffer_unref (buffer);
return GST_FLOW_OK;
}
if (best == NULL || (GST_CLOCK_TIME_IS_VALID (best_time)
&& time < best_time)) {
best = cpad;
best_time = time;
}
best = (GstFlvPad *) cdata;
if (best) {
g_assert (buffer);
best_time = GST_BUFFER_TIMESTAMP (buffer);
} else {
best_time = GST_CLOCK_TIME_NONE;
}
/* The FLV timestamp is an int32 field. For non-live streams error out if a
@ -1503,17 +1474,17 @@ gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data)
if (!mux->streamable && GST_CLOCK_TIME_IS_VALID (best_time)
&& best_time / GST_MSECOND > G_MAXINT32) {
GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS");
eos = TRUE;
gst_buffer_unref (buffer);
buffer = NULL;
best = NULL;
}
if (!eos && best) {
return gst_flv_mux_write_buffer (mux, best);
} else if (eos) {
if (best) {
return gst_flv_mux_write_buffer (mux, best, buffer);
} else {
gst_flv_mux_rewrite_header (mux);
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
return GST_FLOW_EOS;
} else {
return GST_FLOW_OK;
}
}
@ -1565,12 +1536,12 @@ gst_flv_mux_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_collect_pads_start (mux->collect);
gst_collect_pads2_start (mux->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_collect_pads_stop (mux->collect);
gst_collect_pads2_stop (mux->collect);
break;
default:
break;

View file

@ -22,7 +22,7 @@
#define __GST_FLV_MUX_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
G_BEGIN_DECLS
@ -39,7 +39,7 @@ G_BEGIN_DECLS
typedef struct
{
GstCollectData collect;
GstCollectData2 collect;
gboolean video;
@ -65,11 +65,9 @@ typedef struct _GstFlvMux {
GstElement element;
GstPad *srcpad;
GstCollectPads *collect;
GstCollectPads2 *collect;
/* <private> */
GstPadEventFunction collect_event;
GstFlvMuxState state;
gboolean have_audio;
gboolean have_video;

View file

@ -41,6 +41,12 @@
#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/glib-compat-private.h>
#include "gstimagefreeze.h"
static void gst_image_freeze_finalize (GObject * object);

View file

@ -227,7 +227,7 @@ static gboolean gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_interleave_sink_getcaps (GstPad * pad);
static GstFlowReturn gst_interleave_collected (GstCollectPads * pads,
static GstFlowReturn gst_interleave_collected (GstCollectPads2 * pads,
GstInterleave * self);
static void
@ -407,9 +407,9 @@ gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass)
gst_element_add_pad (GST_ELEMENT (self), self->src);
self->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (self->collect,
(GstCollectPadsFunction) gst_interleave_collected, self);
self->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_function (self->collect,
(GstCollectPads2Function) gst_interleave_collected, self);
self->input_channel_positions = g_value_array_new (0);
self->channel_positions_from_input = TRUE;
@ -500,11 +500,10 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
gst_pad_set_getcaps_function (new_pad,
GST_DEBUG_FUNCPTR (gst_interleave_sink_getcaps));
gst_collect_pads_add_pad (self->collect, new_pad, sizeof (GstCollectData),
NULL);
gst_collect_pads2_add_pad (self->collect, new_pad, sizeof (GstCollectData2));
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* GstCollectPads2; because it sets its own event function giving the
* element no access to events */
self->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (new_pad);
gst_pad_set_event_function (new_pad,
@ -550,7 +549,7 @@ not_sink_pad:
could_not_add:
{
GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
gst_collect_pads_remove_pad (self->collect, new_pad);
gst_collect_pads2_remove_pad (self->collect, new_pad);
gst_object_unref (new_pad);
return NULL;
}
@ -604,7 +603,7 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad)
GST_OBJECT_UNLOCK (self->collect);
gst_collect_pads_remove_pad (self->collect, pad);
gst_collect_pads2_remove_pad (self->collect, pad);
gst_element_remove_pad (element, pad);
}
@ -626,7 +625,7 @@ gst_interleave_change_state (GstElement * element, GstStateChange transition)
self->segment_position = 0;
self->segment_rate = 1.0;
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
gst_collect_pads_start (self->collect);
gst_collect_pads2_start (self->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@ -635,11 +634,11 @@ gst_interleave_change_state (GstElement * element, GstStateChange transition)
}
/* Stop before calling the parent's state change function as
* GstCollectPads might take locks and we would deadlock in that
* GstCollectPads2 might take locks and we would deadlock in that
* case
*/
if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
gst_collect_pads_stop (self->collect);
gst_collect_pads2_stop (self->collect);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
@ -879,7 +878,7 @@ gst_interleave_sink_event (GstPad * pad, GstEvent * event)
break;
}
/* now GstCollectPads can take care of the rest, e.g. EOS */
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
ret = self->collect_event (pad, event);
gst_object_unref (self);
@ -1160,7 +1159,7 @@ gst_interleave_src_event (GstPad * pad, GstEvent * event)
/* check if we are flushing */
if (flags & GST_SEEK_FLAG_FLUSH) {
/* make sure we accept nothing anymore and return WRONG_STATE */
gst_collect_pads_set_flushing (self->collect, TRUE);
gst_collect_pads2_set_flushing (self->collect, TRUE);
/* flushing seek, start flush downstream, the flush will be done
* when all pads received a FLUSH_STOP. */
@ -1195,7 +1194,7 @@ gst_interleave_src_event (GstPad * pad, GstEvent * event)
}
static GstFlowReturn
gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
{
guint size;
GstBuffer *outbuf;
@ -1211,7 +1210,7 @@ gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED);
size = gst_collect_pads_available (pads);
size = gst_collect_pads2_available (pads);
g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR);
@ -1238,13 +1237,13 @@ gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels);
for (collected = pads->data; collected != NULL; collected = collected->next) {
GstCollectData *cdata;
GstCollectData2 *cdata;
GstBuffer *inbuf;
guint8 *outdata;
cdata = (GstCollectData *) collected->data;
cdata = (GstCollectData2 *) collected->data;
inbuf = gst_collect_pads_take_buffer (pads, cdata, size);
inbuf = gst_collect_pads2_take_buffer (pads, cdata, size);
if (inbuf == NULL) {
GST_DEBUG_OBJECT (cdata->pad, "No buffer available");
goto next;

View file

@ -27,7 +27,7 @@
#define __INTERLEAVE_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
G_BEGIN_DECLS
@ -49,7 +49,7 @@ struct _GstInterleave
GstElement element;
/*< private >*/
GstCollectPads *collect;
GstCollectPads2 *collect;
gint channels;
gint padcounter;

View file

@ -65,6 +65,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 <glib/gstdio.h>
#include <gst/gst.h>

View file

@ -226,11 +226,11 @@ static GstPad *gst_qt_mux_request_new_pad (GstElement * element,
static void gst_qt_mux_release_pad (GstElement * element, GstPad * pad);
/* event */
static gboolean gst_qt_mux_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean gst_qt_mux_sink_event (GstCollectPads2 * pads,
GstCollectData2 * data, GstEvent * event, gpointer user_data);
static GstFlowReturn gst_qt_mux_collected (GstCollectPads * pads,
gpointer user_data);
static GstFlowReturn gst_qt_mux_handle_buffer (GstCollectPads2 * pads,
GstCollectData2 * cdata, GstBuffer * buf, gpointer user_data);
static GstFlowReturn gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad,
GstBuffer * buf);
@ -482,9 +482,13 @@ gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass)
gst_element_add_pad (GST_ELEMENT (qtmux), qtmux->srcpad);
qtmux->sinkpads = NULL;
qtmux->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (qtmux->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_qt_mux_collected), qtmux);
qtmux->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_buffer_function (qtmux->collect,
GST_DEBUG_FUNCPTR (gst_qt_mux_handle_buffer), qtmux);
gst_collect_pads2_set_event_function (qtmux->collect,
GST_DEBUG_FUNCPTR (gst_qt_mux_sink_event), qtmux);
gst_collect_pads2_set_clip_function (qtmux->collect,
GST_DEBUG_FUNCPTR (gst_collect_pads2_clip_running_time), qtmux);
/* properties set to default upon construction */
@ -1661,7 +1665,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
gst_buffer_unref (prefix);
for (walk = qtmux->sinkpads; walk && !fail; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
GstQTPad *qpad = (GstQTPad *) cdata;
/* write info for each stream */
fail = atoms_recov_write_trak_info (qtmux->moov_recov_file, qpad->trak);
@ -1761,7 +1765,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
/* pushing last buffers for each pad */
for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
GstQTPad *qtpad = (GstQTPad *) cdata;
/* avoid add_buffer complaining if not negotiated
@ -1853,7 +1857,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
/* check for late streams */
first_ts = GST_CLOCK_TIME_NONE;
for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
GstQTPad *qtpad = (GstQTPad *) cdata;
if (!GST_CLOCK_TIME_IS_VALID (first_ts) ||
@ -1866,7 +1870,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
GST_TIME_ARGS (first_ts));
/* add EDTSs for late streams */
for (walk = qtmux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
GstQTPad *qtpad = (GstQTPad *) cdata;
guint32 lateness;
guint32 duration;
@ -2520,14 +2524,13 @@ not_negotiated:
}
static GstFlowReturn
gst_qt_mux_collected (GstCollectPads * pads, gpointer user_data)
gst_qt_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
GstBuffer * buf, gpointer user_data)
{
GstFlowReturn ret = GST_FLOW_OK;
GstQTMux *qtmux = GST_QT_MUX_CAST (user_data);
GSList *walk;
GstQTPad *best_pad = NULL;
GstClockTime time, best_time = GST_CLOCK_TIME_NONE;
GstBuffer *buf;
GstClockTime best_time = GST_CLOCK_TIME_NONE;
if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_STARTED)) {
if ((ret = gst_qt_mux_start_file (qtmux)) != GST_FLOW_OK)
@ -2539,52 +2542,14 @@ gst_qt_mux_collected (GstCollectPads * pads, gpointer user_data)
if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_EOS))
return GST_FLOW_EOS;
/* select the best buffer */
walk = qtmux->collect->data;
while (walk) {
GstQTPad *pad;
GstCollectData *data;
data = (GstCollectData *) walk->data;
pad = (GstQTPad *) data;
walk = g_slist_next (walk);
buf = gst_collect_pads_peek (pads, data);
if (buf == NULL) {
GST_LOG_OBJECT (qtmux, "Pad %s has no buffers",
GST_PAD_NAME (pad->collect.pad));
continue;
}
time = GST_BUFFER_TIMESTAMP (buf);
gst_buffer_unref (buf);
/* invalid should pass */
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
time =
gst_segment_to_running_time (&data->segment, GST_FORMAT_TIME, time);
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
GST_DEBUG_OBJECT (qtmux, "clipping buffer on pad %s outside segment",
GST_PAD_NAME (data->pad));
buf = gst_collect_pads_pop (pads, data);
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
}
if (best_pad == NULL || !GST_CLOCK_TIME_IS_VALID (time) ||
(GST_CLOCK_TIME_IS_VALID (best_time) && time < best_time)) {
best_pad = pad;
best_time = time;
}
}
best_pad = (GstQTPad *) cdata;
/* clipping already converted to running time */
if (best_pad != NULL) {
g_assert (buf);
best_time = GST_BUFFER_TIMESTAMP (buf);
GST_LOG_OBJECT (qtmux, "selected pad %s with time %" GST_TIME_FORMAT,
GST_PAD_NAME (best_pad->collect.pad), GST_TIME_ARGS (best_time));
buf = gst_collect_pads_pop (pads, &best_pad->collect);
buf = gst_buffer_make_writable (buf);
GST_BUFFER_TIMESTAMP (buf) = best_time;
ret = gst_qt_mux_add_buffer (qtmux, best_pad, buf);
} else {
ret = gst_qt_mux_stop_file (qtmux);
@ -3284,14 +3249,14 @@ refuse_renegotiation:
}
static gboolean
gst_qt_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
gst_qt_mux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
GstEvent * event, gpointer user_data)
{
gboolean ret;
GstQTMux *qtmux;
guint32 avg_bitrate = 0, max_bitrate = 0;
GstPad *pad = data->pad;
qtmux = GST_QT_MUX_CAST (parent);
qtmux = GST_QT_MUX_CAST (user_data);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
@ -3316,8 +3281,9 @@ gst_qt_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
GST_OBJECT_LOCK (qtmux);
mode = gst_tag_setter_get_tag_merge_mode (setter);
GST_DEBUG_OBJECT (qtmux, "received tag event");
gst_event_parse_tag (event, &list);
GST_DEBUG_OBJECT (qtmux, "received tag event on pad %s:%s : %"
GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), list);
gst_tag_setter_merge_tags (setter, list, mode);
GST_OBJECT_UNLOCK (qtmux);
@ -3339,9 +3305,8 @@ gst_qt_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
break;
}
ret = qtmux->collect_event (pad, parent, event);
return ret;
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
return FALSE;
}
static void
@ -3363,7 +3328,7 @@ gst_qt_mux_release_pad (GstElement * element, GstPad * pad)
}
}
gst_collect_pads_remove_pad (mux->collect, pad);
gst_collect_pads2_remove_pad (mux->collect, pad);
}
static GstPad *
@ -3407,8 +3372,8 @@ gst_qt_mux_request_new_pad (GstElement * element,
newpad = gst_pad_new_from_template (templ, name);
g_free (name);
collect_pad = (GstQTPad *)
gst_collect_pads_add_pad (qtmux->collect, newpad, sizeof (GstQTPad),
(GstCollectDataDestroyNotify) (gst_qt_mux_pad_reset));
gst_collect_pads2_add_pad_full (qtmux->collect, newpad, sizeof (GstQTPad),
(GstCollectData2DestroyNotify) (gst_qt_mux_pad_reset), TRUE);
/* set up pad */
gst_qt_mux_pad_reset (collect_pad);
collect_pad->trak = atom_trak_new (qtmux->context);
@ -3422,14 +3387,6 @@ gst_qt_mux_request_new_pad (GstElement * element,
else
collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps);
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* element no access to events.
*/
qtmux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
gst_pad_set_event_function (newpad,
GST_DEBUG_FUNCPTR (gst_qt_mux_sink_event));
gst_pad_set_active (newpad, TRUE);
gst_element_add_pad (element, newpad);
@ -3566,13 +3523,13 @@ gst_qt_mux_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_collect_pads_start (qtmux->collect);
gst_collect_pads2_start (qtmux->collect);
qtmux->state = GST_QT_MUX_STATE_STARTED;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_collect_pads_stop (qtmux->collect);
gst_collect_pads2_stop (qtmux->collect);
break;
default:
break;

View file

@ -44,7 +44,7 @@
#define __GST_QT_MUX_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
#include "fourcc.h"
#include "atoms.h"
@ -82,7 +82,7 @@ typedef GstBuffer * (*GstQTPadPrepareBufferFunc) (GstQTPad * pad,
struct _GstQTPad
{
GstCollectData collect; /* we extend the CollectData */
GstCollectData2 collect; /* we extend the CollectData2 */
/* fourcc id of stream */
guint32 fourcc;
@ -145,7 +145,7 @@ struct _GstQTMux
GstElement element;
GstPad *srcpad;
GstCollectPads *collect;
GstCollectPads2 *collect;
GSList *sinkpads;
/* state */
@ -192,9 +192,6 @@ struct _GstQTMux
guint32 fragment_duration;
gboolean streamable;
/* for collect pads event handling function */
GstPadEventFunction collect_event;
/* for request pad naming */
guint video_pads, audio_pads;
};

View file

@ -47,6 +47,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/gst-i18n-plugin.h"
#include <glib/gprintf.h>
@ -5317,8 +5321,13 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
/* make sure there's enough data */
if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 2 * 4))
goto corrupt_file;
if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
stream->n_sample_times);
if (!stream->n_sample_times)
goto corrupt_file;
}
/* sync sample atom */
stream->stps_present = FALSE;

View file

@ -49,6 +49,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 <math.h>
#include <string.h>
#include <glib/gprintf.h>
@ -482,6 +486,8 @@ gst_matroska_demux_reset (GstElement * element)
gst_buffer_unref (demux->common.cached_buffer);
demux->common.cached_buffer = NULL;
}
demux->invalid_duration = FALSE;
}
static GstBuffer *
@ -1356,10 +1362,12 @@ gst_matroska_demux_query (GstMatroskaDemux * demux, GstPad * pad,
GST_OBJECT_LOCK (demux);
if (context)
gst_query_set_position (query, GST_FORMAT_TIME,
context->pos - demux->stream_start_time);
MAX (context->pos, demux->stream_start_time) -
demux->stream_start_time);
else
gst_query_set_position (query, GST_FORMAT_TIME,
demux->common.segment.position - demux->stream_start_time);
MAX (demux->common.segment.position, demux->stream_start_time) -
demux->stream_start_time);
GST_OBJECT_UNLOCK (demux);
} else if (format == GST_FORMAT_DEFAULT && context
&& context->default_duration) {
@ -1740,8 +1748,11 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
otime = demux->common.segment.position;
GST_OBJECT_UNLOCK (demux);
/* sanitize */
time = MAX (time, demux->stream_start_time);
/* avoid division by zero in first estimation below */
if (otime == 0)
if (otime <= demux->stream_start_time)
otime = time;
retry:
@ -1918,6 +1929,14 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
* segment when we close the current segment. */
memcpy (&seeksegment, &demux->common.segment, sizeof (GstSegment));
/* pull mode without index means that the actual duration is not known,
* we might be playing a file that's still being recorded
* so, invalidate our current duration, which is only a moving target,
* and should not be used to clamp anything */
if (!demux->streaming && !demux->common.index && demux->invalid_duration) {
seeksegment.duration = GST_CLOCK_TIME_NONE;
}
if (event) {
GST_DEBUG_OBJECT (demux, "configuring seek");
gst_segment_do_seek (&seeksegment, rate, format, flags,
@ -1932,6 +1951,10 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
}
}
/* restore segment duration (if any effect),
* would be determined again when parsing, but anyway ... */
seeksegment.duration = demux->common.segment.duration;
flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
@ -1952,7 +1975,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
seeksegment.position, &demux->seek_index, &demux->seek_entry)) ==
NULL) {
/* pull mode without index can scan later on */
if (demux->common.index || demux->streaming) {
if (demux->streaming) {
GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
GST_OBJECT_UNLOCK (demux);
return FALSE;
@ -1989,7 +2012,7 @@ next:
GST_PAD_STREAM_LOCK (demux->common.sinkpad);
/* pull mode without index can do some scanning */
if (!demux->streaming && !demux->common.index) {
if (!demux->streaming && !entry) {
/* need to stop flushing upstream as we need it next */
if (flush)
gst_pad_push_event (demux->common.sinkpad,
@ -2011,9 +2034,9 @@ next:
if (keyunit) {
GST_DEBUG_OBJECT (demux, "seek to key unit, adjusting segment start to %"
GST_TIME_FORMAT, GST_TIME_ARGS (entry->time));
seeksegment.start = entry->time;
seeksegment.position = entry->time;
seeksegment.time = entry->time - demux->stream_start_time;
seeksegment.start = MAX (entry->time, demux->stream_start_time);
seeksegment.position = seeksegment.start;
seeksegment.time = seeksegment.start - demux->stream_start_time;
}
exit:
@ -3347,9 +3370,9 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
else if (GST_CLOCK_TIME_IS_VALID (segment->position))
segment_duration = segment->position - segment->start;
segment->base += segment_duration / fabs (segment->rate);
segment->start = lace_time;
segment->start = MAX (lace_time, demux->stream_start_time);
segment->stop = GST_CLOCK_TIME_NONE;
segment->position = lace_time - demux->stream_start_time;
segment->position = segment->start - demux->stream_start_time;
/* now convey our segment notion downstream */
gst_matroska_demux_send_event (demux, gst_event_new_segment (segment));
demux->need_segment = FALSE;
@ -3535,14 +3558,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
GST_OBJECT_LOCK (demux);
if (demux->common.segment.duration == -1 ||
demux->common.segment.duration <
lace_time - demux->stream_start_time) {
demux->stream_start_time + demux->common.segment.duration <
last_stop_end) {
demux->common.segment.duration =
last_stop_end - demux->stream_start_time;
GST_OBJECT_UNLOCK (demux);
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_duration (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, GST_CLOCK_TIME_NONE));
demux->invalid_duration = TRUE;
} else {
GST_OBJECT_UNLOCK (demux);
}
@ -4475,11 +4499,13 @@ pause:
/* Close the segment, i.e. update segment stop with the duration
* if no stop was set */
if (GST_CLOCK_TIME_IS_VALID (demux->last_stop_end) &&
!GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop)) {
!GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop) &&
GST_CLOCK_TIME_IS_VALID (demux->common.segment.start) &&
demux->last_stop_end > demux->common.segment.start) {
GstSegment segment = demux->common.segment;
GstEvent *event;
segment.stop = MAX (demux->last_stop_end, segment.start);
segment.stop = demux->last_stop_end;
event = gst_event_new_segment (&segment);
gst_matroska_demux_send_event (demux, event);
}

View file

@ -95,6 +95,9 @@ typedef struct _GstMatroskaDemux {
/* gap handling */
guint64 max_gap_time;
/* for non-finalized files, with invalid segment duration */
gboolean invalid_duration;
} GstMatroskaDemux;
typedef struct _GstMatroskaDemuxClass {

View file

@ -2,6 +2,7 @@
* (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* (c) 2005 Michal Benes <michal.benes@xeris.cz>
* (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* (c) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
*
* matroska-mux.c: matroska file/stream muxer
*
@ -183,10 +184,14 @@ static GstStaticPadTemplate audiosink_templ =
);
static GstStaticPadTemplate subtitlesink_templ =
GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("subtitle/x-kate"));
GST_STATIC_CAPS ("subtitle/x-kate; "
"text/plain; application/x-ssa; application/x-ass; "
"application/x-usf; video/x-dvd-subpicture; "
"application/x-subtitle-unknown")
);
static GArray *used_uids;
G_LOCK_DEFINE_STATIC (used_uids);
@ -199,8 +204,10 @@ G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
static void gst_matroska_mux_finalize (GObject * object);
/* Pads collected callback */
static GstFlowReturn
gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data);
static GstFlowReturn gst_matroska_mux_handle_buffer (GstCollectPads2 * pads,
GstCollectData2 * data, GstBuffer * buf, gpointer user_data);
static gboolean gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
GstCollectData2 * data, GstEvent * event, gpointer user_data);
/* pad functions */
static gboolean gst_matroska_mux_handle_src_event (GstPad * pad,
@ -415,10 +422,13 @@ gst_matroska_mux_init (GstMatroskaMux * mux)
gst_pad_set_event_function (mux->srcpad, gst_matroska_mux_handle_src_event);
gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
mux->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (mux->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_matroska_mux_collected),
mux);
mux->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_clip_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_collect_pads2_clip_running_time), mux);
gst_collect_pads2_set_buffer_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_buffer), mux);
gst_collect_pads2_set_event_function (mux->collect,
GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event), mux);
mux->ebml_write = gst_ebml_write_new (mux->srcpad);
mux->doctype = GST_MATROSKA_DOCTYPE_MATROSKA;
@ -535,12 +545,6 @@ gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
collect_pad->track = NULL;
}
/* free cached buffer */
if (collect_pad->buffer != NULL) {
gst_buffer_unref (collect_pad->buffer);
collect_pad->buffer = NULL;
}
if (!full && type != 0) {
GstMatroskaTrackContext *context;
@ -568,7 +572,6 @@ gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
/* TODO: check default values for the context */
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
collect_pad->track = context;
collect_pad->buffer = NULL;
collect_pad->duration = 0;
collect_pad->start_ts = GST_CLOCK_TIME_NONE;
collect_pad->end_ts = GST_CLOCK_TIME_NONE;
@ -665,6 +668,44 @@ gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
return gst_pad_event_default (pad, parent, event);
}
static void
gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
const guint * clut)
{
gchar *clutv[17];
gchar *sclut;
gint i;
guint32 col;
gdouble y, u, v;
guint8 r, g, b;
/* produce comma-separated list in hex format */
for (i = 0; i < 16; ++i) {
col = clut[i];
/* replicate vobsub's slightly off RGB conversion calculation */
y = (((col >> 16) & 0xff) - 16) * 255 / 219;
u = ((col >> 8) & 0xff) - 128;
v = (col & 0xff) - 128;
r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
}
clutv[i] = NULL;
sclut = g_strjoinv (",", clutv);
/* build codec private; only palette for now */
g_free (context->codec_priv);
context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
/* include terminating 0 */
context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
g_free (sclut);
for (i = 0; i < 16; ++i) {
g_free (clutv[i]);
}
}
/**
* gst_matroska_mux_handle_sink_event:
* @pad: Pad which received the event.
@ -675,14 +716,21 @@ gst_matroska_mux_handle_src_event (GstPad * pad, GstObject * parent,
* Returns: #TRUE on success.
*/
static gboolean
gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
GstCollectData2 * data, GstEvent * event, gpointer user_data)
{
GstMatroskaTrackContext *context;
GstMatroskaPad *collect_pad;
GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
GstMatroskaTrackContext *context;
GstMatroskaMux *mux;
GstPad *pad;
GstTagList *list;
gboolean ret = TRUE;
gboolean ret = FALSE;
mux = GST_MATROSKA_MUX (user_data);
collect_pad = (GstMatroskaPad *) data;
pad = data->pad;
context = collect_pad->track;
g_assert (context);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:{
@ -702,11 +750,6 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
GST_DEBUG_OBJECT (mux, "received tag event");
gst_event_parse_tag (event, &list);
collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
g_assert (collect_pad);
context = collect_pad->track;
g_assert (context);
/* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
const gchar *lang_code;
@ -735,7 +778,6 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
gst_event_parse_segment (event, &segment);
if (segment->format != GST_FORMAT_TIME) {
ret = FALSE;
gst_event_unref (event);
event = NULL;
}
@ -749,6 +791,31 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
gst_event_replace (&mux->force_key_unit_event, NULL);
mux->force_key_unit_event = event;
event = NULL;
} else if (gst_structure_has_name (structure, "application/x-gst-dvd") &&
!strcmp ("dvd-spu-clut-change",
gst_structure_get_string (structure, "event"))) {
gchar name[16];
gint i, value;
guint clut[16];
GST_DEBUG_OBJECT (pad, "New DVD colour table received");
if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE) {
GST_DEBUG_OBJECT (pad, "... discarding");
break;
}
/* first transform event data into table form */
for (i = 0; i < 16; i++) {
g_snprintf (name, sizeof (name), "clut%02d", i);
if (!gst_structure_get_int (structure, name, &value)) {
GST_ERROR_OBJECT (mux, "dvd-spu-clut-change event did not "
"contain %s field", name);
break;
}
clut[i] = value;
}
/* transform into private data for stream; text form */
gst_matroska_mux_build_vobsub_private (context, clut);
}
break;
}
@ -756,13 +823,19 @@ gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
break;
}
/* now GstCollectPads can take care of the rest, e.g. EOS */
if (event)
ret = mux->collect_event (pad, parent, event);
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
return ret;
}
static void
gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
const char *id)
{
g_assert (context && id);
if (context->codec_id)
g_free (context->codec_id);
context->codec_id = g_strdup (id);
}
/**
* gst_matroska_mux_video_pad_setcaps:
@ -872,12 +945,13 @@ skip_details:
/* find type */
if (!strcmp (mimetype, "video/x-raw")) {
const gchar *fstr;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
fstr = gst_structure_get_string (structure, "format");
if (fstr && strlen (fstr) == 4)
videocontext->fourcc = GST_STR_FOURCC (fstr);
} else if (!strcmp (mimetype, "image/jpeg")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
} else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
||!strcmp (mimetype, "video/x-huffyuv")
|| !strcmp (mimetype, "video/x-divx")
@ -970,11 +1044,13 @@ skip_details:
(guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
}
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
context->codec_priv = (gpointer) bih;
context->codec_priv_size = size;
} else if (!strcmp (mimetype, "video/x-h264")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
@ -991,7 +1067,7 @@ skip_details:
} else if (!strcmp (mimetype, "video/x-theora")) {
const GValue *streamheader;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
@ -1006,22 +1082,25 @@ skip_details:
goto refuse_caps;
}
} else if (!strcmp (mimetype, "video/x-dirac")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_DIRAC);
} else if (!strcmp (mimetype, "video/x-vp8")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VP8);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_VP8);
} else if (!strcmp (mimetype, "video/mpeg")) {
gint mpegversion;
gst_structure_get_int (structure, "mpegversion", &mpegversion);
switch (mpegversion) {
case 1:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_MPEG1);
break;
case 2:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_MPEG2);
break;
case 4:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP);
break;
default:
goto refuse_caps;
@ -1044,16 +1123,20 @@ skip_details:
gst_structure_get_int (structure, "rmversion", &rmversion);
switch (rmversion) {
case 1:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
break;
case 2:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
break;
case 3:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
break;
case 4:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
break;
default:
goto refuse_caps;
@ -1551,13 +1634,16 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
switch (layer) {
case 1:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1);
break;
case 2:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2);
break;
case 3:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3);
break;
default:
goto refuse_caps;
@ -1620,14 +1706,16 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
goto refuse_caps;
}
if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
else
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
break;
case GST_AUDIO_FORMAT_F32LE:
case GST_AUDIO_FORMAT_F64LE:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
break;
default:
@ -1636,11 +1724,10 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
}
audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
} else if (!strcmp (mimetype, "audio/x-vorbis")) {
const GValue *streamheader;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
@ -1657,7 +1744,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
} else if (!strcmp (mimetype, "audio/x-flac")) {
const GValue *streamheader;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_FLAC);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
context->codec_priv = NULL;
@ -1673,7 +1760,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
} else if (!strcmp (mimetype, "audio/x-speex")) {
const GValue *streamheader;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
context->codec_priv = NULL;
@ -1687,11 +1774,11 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
goto refuse_caps;
}
} else if (!strcmp (mimetype, "audio/x-ac3")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
} else if (!strcmp (mimetype, "audio/x-eac3")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_EAC3);
} else if (!strcmp (mimetype, "audio/x-dts")) {
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_DTS);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_DTS);
} else if (!strcmp (mimetype, "audio/x-tta")) {
gint width;
@ -1700,7 +1787,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
gst_structure_get_int (structure, "width", &width);
audiocontext->bitdepth = width;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_TTA);
} else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
gint raversion;
@ -1709,13 +1796,16 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
gst_structure_get_int (structure, "raversion", &raversion);
switch (raversion) {
case 1:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
break;
case 2:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
break;
case 8:
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
break;
default:
goto refuse_caps;
@ -1816,7 +1906,7 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
(guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
}
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
context->codec_priv = (gpointer) codec_priv;
context->codec_priv_size = codec_priv_size;
}
@ -1832,6 +1922,10 @@ refuse_caps:
}
}
/* we probably don't have the data at start,
* so have to reserve (a maximum) space to write this at the end.
* bit spacy, but some formats can hold quite some */
#define SUBTITLE_MAX_CODEC_PRIVATE 2048 /* must be > 128 */
/**
* gst_matroska_mux_subtitle_pad_setcaps:
@ -1845,11 +1939,6 @@ refuse_caps:
static gboolean
gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
{
/* FIXME:
* Consider this as boilerplate code for now. There is
* no single subtitle creation element in GStreamer,
* neither do I know how subtitling works at all. */
/* There is now (at least) one such alement (kateenc), and I'm going
to handle it here and claim it works when it can be piped back
through GStreamer and VLC */
@ -1860,6 +1949,10 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
GstMatroskaPad *collect_pad;
const gchar *mimetype;
GstStructure *structure;
const GValue *value = NULL;
GstBuffer *buf = NULL;
gchar *id = NULL;
gboolean ret = TRUE;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
@ -1874,17 +1967,19 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
/* keep track of default set in request_pad */
id = context->codec_id;
/* general setup */
scontext->check_utf8 = 1;
scontext->invalid_utf8 = 0;
context->default_duration = 0;
/* TODO: - other format than Kate */
if (!strcmp (mimetype, "subtitle/x-kate")) {
const GValue *streamheader;
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_SUBTITLE_KATE);
if (context->codec_priv != NULL) {
g_free (context->codec_priv);
@ -1896,12 +1991,64 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps)
if (!kate_streamheader_to_codecdata (streamheader, context)) {
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
("kate stream headers missing or malformed"));
return FALSE;
ret = FALSE;
goto exit;
}
return TRUE;
} else if (!strcmp (mimetype, "text/plain")) {
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
} else if (!strcmp (mimetype, "application/x-ssa")) {
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
} else if (!strcmp (mimetype, "application/x-ass")) {
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
} else if (!strcmp (mimetype, "application/x-usf")) {
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
} else if (!strcmp (mimetype, "video/x-dvd-subpicture")) {
gst_matroska_mux_set_codec_id (context,
GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
} else {
id = NULL;
ret = FALSE;
goto exit;
}
return FALSE;
/* maybe some private data, e.g. vobsub */
value = gst_structure_get_value (structure, "codec_data");
if (value)
buf = gst_value_get_buffer (value);
if (buf != NULL) {
guint8 *priv_data = NULL, *priv_buffer_data;
gsize priv_data_size = 0;
priv_buffer_data =
gst_buffer_map (buf, &priv_data_size, NULL, GST_MAP_READ);
if (priv_data_size > SUBTITLE_MAX_CODEC_PRIVATE) {
GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
" exceeded maximum (%d); discarding", pad,
SUBTITLE_MAX_CODEC_PRIVATE);
gst_buffer_unmap (buf, priv_data, priv_data_size);
return TRUE;
}
if (context->codec_priv != NULL)
g_free (context->codec_priv);
priv_data = g_malloc0 (priv_data_size);
memcpy (priv_data, priv_buffer_data, priv_data_size);
context->codec_priv = priv_data;
context->codec_priv_size = priv_data_size;
gst_buffer_unmap (buf, priv_buffer_data, priv_data_size);
}
GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %u",
GST_STR_NULL (context->codec_id), context->codec_priv_size);
exit:
/* free default if modified */
if (id)
g_free (id);
return ret;
}
@ -1928,6 +2075,8 @@ gst_matroska_mux_request_new_pad (GstElement * element,
GstMatroskaCapsFunc capsfunc = NULL;
GstMatroskaTrackContext *context = NULL;
gint pad_id;
gboolean locked = TRUE;
gchar *id = NULL;
if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
@ -1971,6 +2120,9 @@ gst_matroska_mux_request_new_pad (GstElement * element,
g_new0 (GstMatroskaTrackSubtitleContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_SUBTITLE;
context->name = g_strdup ("Subtitle");
/* setcaps may only provide proper one a lot later */
id = g_strdup ("S_SUB_UNKNOWN");
locked = FALSE;
} else {
GST_WARNING_OBJECT (mux, "This is not our template!");
return NULL;
@ -1982,24 +2134,13 @@ gst_matroska_mux_request_new_pad (GstElement * element,
gst_matroskamux_pad_init (newpad);
collect_pad = (GstMatroskaPad *)
gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad),
sizeof (GstMatroskaPad),
(GstCollectDataDestroyNotify) gst_matroska_pad_free);
gst_collect_pads2_add_pad_full (mux->collect, GST_PAD (newpad),
sizeof (GstMatroskamuxPad),
(GstCollectData2DestroyNotify) gst_matroska_pad_free, locked);
collect_pad->track = context;
gst_matroska_pad_reset (collect_pad, FALSE);
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving the
* element no access to events.
* TODO GstCollectPads should really give its 'users' a clean chance to
* properly handle events that are not meant for collectpads itself.
* Perhaps a callback or so, though rejected (?) in #340060.
* This would allow (clean) transcoding of info from demuxer/streams
* to another muxer */
mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
gst_pad_set_event_function (GST_PAD (newpad),
GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
collect_pad->track->codec_id = id;
collect_pad->capsfunc = capsfunc;
gst_pad_set_active (GST_PAD (newpad), TRUE);
@ -2037,7 +2178,7 @@ gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstCollectData2 *cdata = (GstCollectData2 *) walk->data;
GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
if (cdata->pad == pad) {
@ -2058,7 +2199,7 @@ gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
}
}
gst_collect_pads_remove_pad (mux->collect, pad);
gst_collect_pads2_remove_pad (mux->collect, pad);
if (gst_element_remove_pad (element, pad))
mux->num_streams--;
}
@ -2095,6 +2236,14 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
context->language);
}
/* FIXME: until we have a nice way of getting the codecname
* out of the caps, I'm not going to enable this. Too much
* (useless, double, boring) work... */
/* TODO: Use value from tags if any */
/*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
context->codec_name); */
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
/* type-specific stuff */
switch (context->type) {
case GST_MATROSKA_TRACK_TYPE_VIDEO:{
@ -2145,6 +2294,24 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
break;
}
/* this is what we write for now and must be filled
* and remainder void'ed later on */
#define SUBTITLE_DUMMY_SIZE (1 + 1 + 14 + 1 + 2 + SUBTITLE_MAX_CODEC_PRIVATE)
case GST_MATROSKA_TRACK_TYPE_SUBTITLE:{
gpointer buf;
context->pos = ebml->pos;
/* CodecID is mandatory ... */
gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, "S_SUB_UNKNOWN");
/* reserve space */
buf = g_malloc0 (SUBTITLE_MAX_CODEC_PRIVATE);
gst_ebml_write_binary (ebml, GST_EBML_ID_VOID, buf,
SUBTITLE_MAX_CODEC_PRIVATE);
g_free (buf);
/* real data has to be written at finish */
return;
}
default:
/* doesn't need type-specific data */
break;
@ -2154,13 +2321,6 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
if (context->codec_priv)
gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
context->codec_priv, context->codec_priv_size);
/* FIXME: until we have a nice way of getting the codecname
* out of the caps, I'm not going to enable this. Too much
* (useless, double, boring) work... */
/* TODO: Use value from tags if any */
/*gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CODECNAME,
context->codec_name); */
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_TRACKNAME, context->name);
}
@ -2230,7 +2390,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
if (tags != NULL && !gst_tag_list_is_empty (tags)) {
guint64 master_tags, master_tag;
GST_DEBUG ("Writing tags");
GST_DEBUG_OBJECT (mux, "Writing tags");
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
mux->tags_pos = ebml->pos;
@ -2304,7 +2464,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
gst_matroska_mux_track_header (mux, collect_pad->track);
gst_ebml_write_master_finish (ebml, child);
/* some remaing pad/track setup */
/* some remaining pad/track setup */
collect_pad->default_duration_scaled =
gst_util_uint64_scale (collect_pad->track->default_duration,
1, mux->time_scale);
@ -2431,7 +2591,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
if (tags != NULL && !gst_tag_list_is_empty (tags)) {
guint64 master_tags, master_tag;
GST_DEBUG ("Writing tags");
GST_DEBUG_OBJECT (mux, "Writing tags");
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
mux->tags_pos = ebml->pos;
@ -2479,16 +2639,23 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
gst_ebml_write_seek (ebml, my_pos);
}
/* update duration */
/* first get the overall duration */
/* a released track may have left a duration in here */
/* loop tracks:
* - first get the overall duration
* (a released track may have left a duration in here)
* - write some track header data for subtitles
*/
duration = mux->duration;
pos = ebml->pos;
for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad;
GstClockTime min_duration; /* observed minimum duration */
GstMatroskaTrackContext *context;
gint voidleft = 0, fill = 0;
gpointer codec_id;
collect_pad = (GstMatroskaPad *) collected->data;
context = collect_pad->track;
GST_DEBUG_OBJECT (mux,
"Pad %" GST_PTR_FORMAT " start ts %" GST_TIME_FORMAT
@ -2510,7 +2677,41 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
if (GST_CLOCK_TIME_IS_VALID (collect_pad->duration) &&
duration < collect_pad->duration)
duration = collect_pad->duration;
if (context->type != GST_MATROSKA_TRACK_TYPE_SUBTITLE || !context->pos)
continue;
again:
/* write subtitle type and possible private data */
gst_ebml_write_seek (ebml, context->pos);
/* complex way to write ascii to account for extra filling */
codec_id = g_malloc0 (strlen (context->codec_id) + 1 + fill);
strcpy (codec_id, context->codec_id);
gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECID,
codec_id, strlen (context->codec_id) + 1 + fill);
g_free (codec_id);
if (context->codec_priv)
gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE,
context->codec_priv, context->codec_priv_size);
voidleft = SUBTITLE_DUMMY_SIZE - (ebml->pos - context->pos);
/* void'ify; sigh, variable sized length field */
if (voidleft == 1) {
fill = 1;
goto again;
} else if (voidleft && voidleft <= 128)
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 2);
else if (voidleft >= 130)
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, voidleft - 3);
else if (voidleft == 129) {
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 64);
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 63);
}
}
/* seek back (optional, but do anyway) */
gst_ebml_write_seek (ebml, pos);
/* update duration */
if (duration != 0) {
GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
GST_TIME_ARGS (duration));
@ -2533,77 +2734,6 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
gst_ebml_write_master_finish (ebml, mux->segment_pos);
}
/**
* gst_matroska_mux_best_pad:
* @mux: #GstMatroskaMux
* @popped: True if at least one buffer was popped from #GstCollectPads
*
* Find a pad with the oldest data
* (data from this pad should be written first).
*
* Returns: Selected pad.
*/
static GstMatroskaPad *
gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
{
GSList *collected;
GstMatroskaPad *best = NULL;
*popped = FALSE;
for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad;
collect_pad = (GstMatroskaPad *) collected->data;
/* fetch a new buffer if needed */
if (collect_pad->buffer == NULL) {
collect_pad->buffer = gst_collect_pads_pop (mux->collect,
(GstCollectData *) collect_pad);
if (collect_pad->buffer != NULL) {
GstClockTime time;
*popped = TRUE;
/* convert to running time */
time = GST_BUFFER_TIMESTAMP (collect_pad->buffer);
/* invalid should pass */
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
time = gst_segment_to_running_time (&collect_pad->collect.segment,
GST_FORMAT_TIME, time);
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
GST_DEBUG_OBJECT (mux, "clipping buffer on pad %s outside segment",
GST_PAD_NAME (collect_pad->collect.pad));
gst_buffer_unref (collect_pad->buffer);
collect_pad->buffer = NULL;
return NULL;
} else {
GST_LOG_OBJECT (mux, "buffer ts %" GST_TIME_FORMAT " -> %"
GST_TIME_FORMAT " running time",
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (collect_pad->buffer)),
GST_TIME_ARGS (time));
collect_pad->buffer =
gst_buffer_make_writable (collect_pad->buffer);
GST_BUFFER_TIMESTAMP (collect_pad->buffer) = time;
}
}
}
}
/* if we have a buffer check if it is better then the current best one */
if (collect_pad->buffer != NULL) {
if (best == NULL || !GST_BUFFER_TIMESTAMP_IS_VALID (collect_pad->buffer)
|| (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)
&& GST_BUFFER_TIMESTAMP (collect_pad->buffer) <
GST_BUFFER_TIMESTAMP (best->buffer))) {
best = collect_pad;
}
}
}
return best;
}
/**
* gst_matroska_mux_buffer_header:
* @track: Track context.
@ -2749,10 +2879,11 @@ gst_matroska_mux_stop_streamheader (GstMatroskaMux * mux)
* Returns: Result of the gst_pad_push issued to write the data.
*/
static GstFlowReturn
gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
GstBuffer * buf)
{
GstEbmlWrite *ebml = mux->ebml_write;
GstBuffer *buf, *hdr;
GstBuffer *hdr;
guint64 blockgroup;
gboolean write_duration;
gint16 relative_timestamp;
@ -2762,8 +2893,6 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
GstMatroskamuxPad *pad;
/* write data */
buf = collect_pad->buffer;
collect_pad->buffer = NULL;
pad = GST_MATROSKAMUX_PAD_CAST (collect_pad->collect.pad);
/* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
@ -2953,10 +3082,9 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
}
}
/**
* gst_matroska_mux_collected:
* @pads: #GstCollectPads
* gst_matroska_mux_handle_buffer:
* @pads: #GstCollectPads2
* @uuser_data: #GstMatroskaMux
*
* Collectpads callback.
@ -2964,12 +3092,12 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
* Returns: #GstFlowReturn
*/
static GstFlowReturn
gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
gst_matroska_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * data,
GstBuffer * buf, gpointer user_data)
{
GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
GstEbmlWrite *ebml = mux->ebml_write;
GstMatroskaPad *best;
gboolean popped;
GstFlowReturn ret = GST_FLOW_OK;
GST_DEBUG_OBJECT (mux, "Collected pads");
@ -2988,53 +3116,53 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
mux->state = GST_MATROSKA_MUX_STATE_DATA;
}
do {
/* which stream to write from? */
best = gst_matroska_mux_best_pad (mux, &popped);
/* provided with stream to write from */
best = (GstMatroskaPad *) data;
/* if there is no best pad, we have reached EOS */
if (best == NULL) {
/* buffer popped, but none returned means it was clipped */
if (popped)
break;
GST_DEBUG_OBJECT (mux, "No best pad finishing...");
if (!mux->streamable) {
gst_matroska_mux_finish (mux);
} else {
GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
}
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
ret = GST_FLOW_EOS;
break;
/* if there is no best pad, we have reached EOS */
if (best == NULL) {
GST_DEBUG_OBJECT (mux, "No best pad finishing...");
if (!mux->streamable) {
gst_matroska_mux_finish (mux);
} else {
GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
}
GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
ret = GST_FLOW_EOS;
goto exit;
}
/* make note of first and last encountered timestamps, so we can calculate
* the actual duration later when we send an updated header on eos */
if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
GstClockTime end_ts = start_ts;
/* if we have a best stream, should also have a buffer */
g_assert (buf);
if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
end_ts += GST_BUFFER_DURATION (best->buffer);
else if (best->track->default_duration)
end_ts += best->track->default_duration;
GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
best->end_ts = end_ts;
/* make note of first and last encountered timestamps, so we can calculate
* the actual duration later when we send an updated header on eos */
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
GstClockTime start_ts = GST_BUFFER_TIMESTAMP (buf);
GstClockTime end_ts = start_ts;
if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
start_ts < best->start_ts))
best->start_ts = start_ts;
}
if (GST_BUFFER_DURATION_IS_VALID (buf))
end_ts += GST_BUFFER_DURATION (buf);
else if (best->track->default_duration)
end_ts += best->track->default_duration;
/* write one buffer */
ret = gst_matroska_mux_write_data (mux, best);
} while (ret == GST_FLOW_OK && !popped);
if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
best->end_ts = end_ts;
if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
start_ts < best->start_ts))
best->start_ts = start_ts;
}
/* write one buffer */
ret = gst_matroska_mux_write_data (mux, best, buf);
exit:
return ret;
}
@ -3058,12 +3186,12 @@ gst_matroska_mux_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_collect_pads_start (mux->collect);
gst_collect_pads2_start (mux->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_collect_pads_stop (mux->collect);
gst_collect_pads2_stop (mux->collect);
break;
default:
break;

View file

@ -24,7 +24,7 @@
#define __GST_MATROSKA_MUX_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
#include "ebml-write.h"
#include "matroska-ids.h"
@ -58,12 +58,10 @@ typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps);
/* all information needed for one matroska stream */
typedef struct
{
GstCollectData collect; /* we extend the CollectData */
GstCollectData2 collect; /* we extend the CollectData */
GstMatroskaCapsFunc capsfunc;
GstMatroskaTrackContext *track;
GstBuffer *buffer; /* the queued buffer for this pad */
guint64 duration;
GstClockTime start_ts;
GstClockTime end_ts; /* last timestamp + (if available) duration */
@ -79,8 +77,7 @@ typedef struct _GstMatroskaMux {
/* pads */
GstPad *srcpad;
GstCollectPads *collect;
GstPadEventFunction collect_event;
GstCollectPads2 *collect;
GstEbmlWrite *ebml_write;
guint num_streams,

View file

@ -999,6 +999,21 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
/* (e.g.) lavf typically creates entries without a block number,
* which is bogus and leads to contradictory information */
if (common->index->len) {
GstMatroskaIndex *last_idx;
last_idx = &g_array_index (common->index, GstMatroskaIndex,
common->index->len - 1);
if (last_idx->block == idx.block && last_idx->pos == idx.pos &&
last_idx->track == idx.track && idx.time > last_idx->time) {
GST_DEBUG_OBJECT (common, "Cue entry refers to same location, "
"but has different time than previous entry; discarding");
idx.track = 0;
}
}
if ((ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
&& idx.pos != (guint64) - 1 && idx.track > 0) {
g_array_append_val (common->index, idx);

View file

@ -655,12 +655,17 @@ write_error:
return GST_FLOW_ERROR;
}
stdio_write_error:
{
GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
("Error while writing to file."), (NULL));
gst_buffer_unmap (buffer, data, size);
return GST_FLOW_ERROR;
switch (errno) {
case ENOSPC:
GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT,
("Error while writing to file."), ("%s", g_strerror (errno)));
break;
default:
GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
("Error while writing to file."), ("%s", g_strerror (errno)));
}
gst_buffer_unmap (buffer, data, size);
return GST_FLOW_ERROR;
}
static gboolean

View file

@ -84,7 +84,7 @@ static GstPad *gst_multipart_mux_request_new_pad (GstElement * element,
static GstStateChangeReturn gst_multipart_mux_change_state (GstElement *
element, GstStateChange transition);
static GstFlowReturn gst_multipart_mux_collected (GstCollectPads * pads,
static GstFlowReturn gst_multipart_mux_collected (GstCollectPads2 * pads,
GstMultipartMux * mux);
static void gst_multipart_mux_set_property (GObject * object, guint prop_id,
@ -148,9 +148,9 @@ gst_multipart_mux_init (GstMultipartMux * multipart_mux)
multipart_mux->boundary = g_strdup (DEFAULT_BOUNDARY);
multipart_mux->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (multipart_mux->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_multipart_mux_collected),
multipart_mux->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_function (multipart_mux->collect,
(GstCollectPads2Function) GST_DEBUG_FUNCPTR (gst_multipart_mux_collected),
multipart_mux);
}
@ -194,8 +194,8 @@ gst_multipart_mux_request_new_pad (GstElement * element,
GstMultipartPadData *multipartpad;
multipartpad = (GstMultipartPadData *)
gst_collect_pads_add_pad (multipart_mux->collect, newpad,
sizeof (GstMultipartPadData), NULL);
gst_collect_pads2_add_pad (multipart_mux->collect, newpad,
sizeof (GstMultipartPadData));
/* save a pointer to our data in the pad */
multipartpad->pad = newpad;
@ -340,7 +340,7 @@ gst_multipart_mux_queue_pads (GstMultipartMux * mux)
/* try to make sure we have a buffer from each usable pad first */
walk = mux->collect->data;
while (walk) {
GstCollectData *data = (GstCollectData *) walk->data;
GstCollectData2 *data = (GstCollectData2 *) walk->data;
GstMultipartPadData *pad = (GstMultipartPadData *) data;
walk = g_slist_next (walk);
@ -349,7 +349,7 @@ gst_multipart_mux_queue_pads (GstMultipartMux * mux)
if (pad->buffer == NULL) {
GstBuffer *buf = NULL;
buf = gst_collect_pads_pop (mux->collect, data);
buf = gst_collect_pads2_pop (mux->collect, data);
/* Store timestamp with segment_start and preroll */
if (buf && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
@ -383,7 +383,7 @@ gst_multipart_mux_queue_pads (GstMultipartMux * mux)
* 3) push both buffers on best pad, go to 1
*/
static GstFlowReturn
gst_multipart_mux_collected (GstCollectPads * pads, GstMultipartMux * mux)
gst_multipart_mux_collected (GstCollectPads2 * pads, GstMultipartMux * mux)
{
GstMultipartPadData *best;
GstFlowReturn ret = GST_FLOW_OK;
@ -605,11 +605,11 @@ gst_multipart_mux_change_state (GstElement * element, GstStateChange transition)
multipart_mux->negotiated = FALSE;
multipart_mux->need_segment = TRUE;
GST_DEBUG_OBJECT (multipart_mux, "starting collect pads");
gst_collect_pads_start (multipart_mux->collect);
gst_collect_pads2_start (multipart_mux->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG_OBJECT (multipart_mux, "stopping collect pads");
gst_collect_pads_stop (multipart_mux->collect);
gst_collect_pads2_stop (multipart_mux->collect);
break;
default:
break;

View file

@ -23,7 +23,7 @@
#define __GST_MULTIPART_MUX__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
#include <string.h>
@ -42,7 +42,7 @@ typedef struct _GstMultipartMuxClass GstMultipartMuxClass;
/* all information needed for one multipart stream */
typedef struct
{
GstCollectData collect; /* we extend the CollectData */
GstCollectData2 collect; /* we extend the CollectData2 */
GstBuffer *buffer; /* the queued buffer for this pad */
GstClockTime timestamp; /* its timestamp, converted to running_time so that we can
@ -64,7 +64,7 @@ struct _GstMultipartMux
GstPad *srcpad;
/* sinkpads */
GstCollectPads *collect;
GstCollectPads2 *collect;
gint numpads;

View file

@ -129,6 +129,8 @@
#include "gstrtpsession.h"
#include "gstrtpjitterbuffer.h"
#include <gst/glib-compat-private.h>
GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug);
#define GST_CAT_DEFAULT gst_rtp_bin_debug

View file

@ -67,6 +67,8 @@
#include "rtpjitterbuffer.h"
#include "rtpstats.h"
#include <gst/glib-compat-private.h>
GST_DEBUG_CATEGORY (rtpjitterbuffer_debug);
#define GST_CAT_DEFAULT (rtpjitterbuffer_debug)

View file

@ -114,6 +114,8 @@
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/glib-compat-private.h>
#include "gstrtpbin-marshal.h"
#include "gstrtpsession.h"
#include "rtpsession.h"
@ -908,8 +910,13 @@ start_rtcp_thread (GstRtpSession * rtpsession)
g_thread_join (rtpsession->priv->thread);
/* only create a new thread if the old one was stopped. Otherwise we can
* just reuse the currently running one. */
#if !GLIB_CHECK_VERSION (2, 31, 0)
rtpsession->priv->thread =
g_thread_create ((GThreadFunc) rtcp_thread, rtpsession, TRUE, &error);
#else
rtpsession->priv->thread = g_thread_try_new ("rtpsession-rtcp-thread",
(GThreadFunc) rtcp_thread, rtpsession, &error);
#endif
rtpsession->priv->thread_stopped = FALSE;
}
GST_RTP_SESSION_UNLOCK (rtpsession);

View file

@ -44,6 +44,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 <string.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>

View file

@ -22,6 +22,8 @@
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include <gst/glib-compat-private.h>
#include "gstrtpbin-marshal.h"
#include "rtpsession.h"

View file

@ -81,6 +81,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
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */

View file

@ -152,7 +152,7 @@ static void gst_smpte_base_init (GstSMPTEClass * klass);
static void gst_smpte_init (GstSMPTE * smpte);
static void gst_smpte_finalize (GstSMPTE * smpte);
static GstFlowReturn gst_smpte_collected (GstCollectPads * pads,
static GstFlowReturn gst_smpte_collected (GstCollectPads2 * pads,
GstSMPTE * smpte);
static void gst_smpte_set_property (GObject * object, guint prop_id,
@ -360,15 +360,15 @@ gst_smpte_init (GstSMPTE * smpte)
gst_pad_new_from_static_template (&gst_smpte_src_template, "src");
gst_element_add_pad (GST_ELEMENT (smpte), smpte->srcpad);
smpte->collect = gst_collect_pads_new ();
gst_collect_pads_set_function (smpte->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_smpte_collected), smpte);
gst_collect_pads_start (smpte->collect);
smpte->collect = gst_collect_pads2_new ();
gst_collect_pads2_set_function (smpte->collect,
(GstCollectPads2Function) GST_DEBUG_FUNCPTR (gst_smpte_collected), smpte);
gst_collect_pads2_start (smpte->collect);
gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad1,
sizeof (GstCollectData), NULL);
gst_collect_pads_add_pad (smpte->collect, smpte->sinkpad2,
sizeof (GstCollectData), NULL);
gst_collect_pads2_add_pad (smpte->collect, smpte->sinkpad1,
sizeof (GstCollectData2));
gst_collect_pads2_add_pad (smpte->collect, smpte->sinkpad2,
sizeof (GstCollectData2));
smpte->fps = DEFAULT_PROP_FPS;
smpte->type = DEFAULT_PROP_TYPE;
@ -441,7 +441,7 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask,
}
static GstFlowReturn
gst_smpte_collected (GstCollectPads * pads, GstSMPTE * smpte)
gst_smpte_collected (GstCollectPads2 * pads, GstSMPTE * smpte)
{
GstBuffer *outbuf;
GstClockTime ts;
@ -458,14 +458,14 @@ gst_smpte_collected (GstCollectPads * pads, GstSMPTE * smpte)
smpte->fps_denom, smpte->fps_num);
for (collected = pads->data; collected; collected = g_slist_next (collected)) {
GstCollectData *data;
GstCollectData2 *data;
data = (GstCollectData *) collected->data;
data = (GstCollectData2 *) collected->data;
if (data->pad == smpte->sinkpad1)
in1 = gst_collect_pads_pop (pads, data);
in1 = gst_collect_pads2_pop (pads, data);
else if (data->pad == smpte->sinkpad2)
in2 = gst_collect_pads_pop (pads, data);
in2 = gst_collect_pads2_pop (pads, data);
}
if (in1 == NULL) {
@ -623,11 +623,11 @@ gst_smpte_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_smpte_reset (smpte);
GST_LOG_OBJECT (smpte, "starting collectpads");
gst_collect_pads_start (smpte->collect);
gst_collect_pads2_start (smpte->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_LOG_OBJECT (smpte, "stopping collectpads");
gst_collect_pads_stop (smpte->collect);
gst_collect_pads2_stop (smpte->collect);
break;
default:
break;

View file

@ -22,7 +22,7 @@
#define __GST_SMPTE_H__
#include <gst/gst.h>
#include <gst/base/gstcollectpads.h>
#include <gst/base/gstcollectpads2.h>
G_BEGIN_DECLS
@ -49,7 +49,7 @@ struct _GstSMPTE {
GstPad *srcpad,
*sinkpad1,
*sinkpad2;
GstCollectPads *collect;
GstCollectPads2 *collect;
/* properties */
gint type;

View file

@ -41,6 +41,8 @@
#include <errno.h>
#include <string.h>
#include "gst/glib-compat-private.h"
GST_DEBUG_CATEGORY_STATIC (multiudpsink_debug);
#define GST_CAT_DEFAULT (multiudpsink_debug)

View file

@ -471,12 +471,21 @@ retry:
IOCTL_SOCKET (udpsrc->sock.fd, FIONREAD, &readsize)) < 0))
goto ioctl_failed;
/* if we get here and there is nothing to read from the socket, the select got
* woken up by activity on the socket but it was not a read. We know someone
* will also do something with the socket so that we don't go into an infinite
* loop in the select(). */
/* If we get here and the readsize is zero, then either select was woken up
* by activity that is not a read, or a poll error occurred, or a UDP packet
* was received that has no data. Since we cannot identify which case it is,
* we handle all of them. This could possibly lead to a UDP packet getting
* lost, but since UDP is not reliable, we can accept this. */
if (G_UNLIKELY (!readsize)) {
/* try to read a packet (and it will be ignored),
* in case a packet with no data arrived */
slen = sizeof (sa);
recvfrom (udpsrc->sock.fd, (char *) &slen, 0, 0, &sa.sa, &slen);
/* clear any error, in case a poll error occurred */
clear_error (udpsrc);
/* poll again */
goto retry;
}

View file

@ -43,6 +43,8 @@
#include "gstaspectratiocrop.h"
#include "gst/glib-compat-private.h"
GST_DEBUG_CATEGORY_STATIC (aspect_ratio_crop_debug);
#define GST_CAT_DEFAULT aspect_ratio_crop_debug

View file

@ -86,6 +86,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 <string.h>
#include "videomixer2.h"

View file

@ -49,6 +49,11 @@
#ifdef HAVE_CONFIG_H
#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 <string.h>
#include <math.h>
@ -85,6 +90,19 @@ static void gst_wavparse_loop (GstPad * pad);
static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static void gst_wavparse_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_wavparse_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
#define DEFAULT_IGNORE_LENGTH FALSE
enum
{
PROP_0,
PROP_IGNORE_LENGTH,
};
static GstStaticPadTemplate sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@ -113,6 +131,27 @@ gst_wavparse_class_init (GstWavParseClass * klass)
object_class->dispose = gst_wavparse_dispose;
object_class->set_property = gst_wavparse_set_property;
object_class->get_property = gst_wavparse_get_property;
/**
* GstWavParse:ignore-length
*
* This selects whether the length found in a data chunk
* should be ignored. This may be useful for streamed audio
* where the length is unknown until the end of streaming,
* and various software/hardware just puts some random value
* in there and hopes it doesn't break too much.
*
* Since: 0.10.36
*/
g_object_class_install_property (object_class, PROP_IGNORE_LENGTH,
g_param_spec_boolean ("ignore-length",
"Ignore length",
"Ignore length from the Wave header",
DEFAULT_IGNORE_LENGTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
gstelement_class->change_state = gst_wavparse_change_state;
gstelement_class->send_event = gst_wavparse_send_event;
@ -212,37 +251,6 @@ gst_wavparse_init (GstWavParse * wavparse)
gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->srcpad);
}
/* Compute (value * nom) % denom, avoiding overflow. This can be used
* to perform ceiling or rounding division together with
* gst_util_uint64_scale[_int]. */
#define uint64_scale_modulo(val, nom, denom) \
((val % denom) * (nom % denom) % denom)
/* Like gst_util_uint64_scale, but performs ceiling division. */
static guint64
uint64_ceiling_scale_int (guint64 val, gint num, gint denom)
{
guint64 result = gst_util_uint64_scale_int (val, num, denom);
if (uint64_scale_modulo (val, num, denom) == 0)
return result;
else
return result + 1;
}
/* Like gst_util_uint64_scale, but performs ceiling division. */
static guint64
uint64_ceiling_scale (guint64 val, guint64 num, guint64 denom)
{
guint64 result = gst_util_uint64_scale (val, num, denom);
if (uint64_scale_modulo (val, num, denom) == 0)
return result;
else
return result + 1;
}
/* FIXME: why is that not in use? */
#if 0
static void
@ -531,7 +539,7 @@ gst_wavparse_fmt (GstWavParse * wav)
gst_element_add_pad (GST_ELEMENT_CAST (wav), wav->srcpad);
gst_element_no_more_pads (GST_ELEMENT_CAST (wav));
GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels);
GST_DEBUG ("frequency %u, channels %u", wav->rate, wav->channels);
return TRUE;
@ -572,8 +580,8 @@ gst_wavparse_other (GstWavParse * wav)
GST_WARNING_OBJECT (wav, "could not peek head");
return FALSE;
}
GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %d", tag,
(gchar *) & tag, length);
GST_DEBUG_OBJECT (wav, "got tag (%08x) %4.4s, length %u", tag,
(const gchar *) &tag, length);
switch (tag) {
case GST_RIFF_TAG_LIST:
@ -724,12 +732,12 @@ gst_wavparse_time_to_bytepos (GstWavParse * wav, gint64 ts, gint64 * bytepos)
}
if (wav->bps > 0) {
*bytepos = uint64_ceiling_scale (ts, (guint64) wav->bps, GST_SECOND);
*bytepos = gst_util_uint64_scale_ceil (ts, (guint64) wav->bps, GST_SECOND);
return TRUE;
} else if (wav->fact) {
guint64 bps =
gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
*bytepos = uint64_ceiling_scale (ts, bps, GST_SECOND);
*bytepos = gst_util_uint64_scale_ceil (ts, bps, GST_SECOND);
return TRUE;
}
@ -1008,7 +1016,7 @@ gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size)
*size = GST_READ_UINT32_LE (data + 4);
gst_adapter_unmap (wav->adapter);
GST_DEBUG ("Next chunk size is %d bytes, type %" GST_FOURCC_FORMAT, *size,
GST_DEBUG ("Next chunk size is %u bytes, type %" GST_FOURCC_FORMAT, *size,
GST_FOURCC_ARGS (*tag));
return TRUE;
@ -1038,7 +1046,7 @@ gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size)
* so we throw poor man's exception, which can be caught if caller really
* wants to handle 0 size chunk */
if (!(*size) || (*size) >= (1 << 30)) {
GST_INFO ("Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT,
GST_INFO ("Invalid/unexpected chunk size %u for tag %" GST_FOURCC_FORMAT,
*size, GST_FOURCC_ARGS (*tag));
/* chain should give up */
wav->abort_buffering = TRUE;
@ -1073,12 +1081,14 @@ gst_wavparse_calculate_duration (GstWavParse * wav)
if (wav->bps > 0) {
GST_INFO_OBJECT (wav, "Got datasize %" G_GUINT64_FORMAT, wav->datasize);
wav->duration =
uint64_ceiling_scale (wav->datasize, GST_SECOND, (guint64) wav->bps);
gst_util_uint64_scale_ceil (wav->datasize, GST_SECOND,
(guint64) wav->bps);
GST_INFO_OBJECT (wav, "Got duration (bps) %" GST_TIME_FORMAT,
GST_TIME_ARGS (wav->duration));
return TRUE;
} else if (wav->fact) {
wav->duration = uint64_ceiling_scale_int (GST_SECOND, wav->fact, wav->rate);
wav->duration =
gst_util_uint64_scale_int_ceil (GST_SECOND, wav->fact, wav->rate);
GST_INFO_OBJECT (wav, "Got duration (fact) %" GST_TIME_FORMAT,
GST_TIME_ARGS (wav->duration));
return TRUE;
@ -1211,12 +1221,12 @@ gst_wavparse_stream_headers (GstWavParse * wav)
{
/* Note: workaround for mp2/mp3 embedded in wav, that relies on the
* bitrate inside the mpeg stream */
GST_INFO ("resetting bps from %d to 0 for mp2/3", wav->av_bps);
GST_INFO ("resetting bps from %u to 0 for mp2/3", wav->av_bps);
wav->bps = 0;
break;
}
case GST_RIFF_WAVE_FORMAT_PCM:
if (wav->blockalign > wav->channels * (guint) ceil (wav->depth / 8.0))
if (wav->blockalign > wav->channels * ((wav->depth + 7) / 8))
goto invalid_blockalign;
/* fall through */
default:
@ -1298,7 +1308,11 @@ gst_wavparse_stream_headers (GstWavParse * wav)
*/
switch (tag) {
case GST_RIFF_TAG_data:{
GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size);
GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %u", size);
if (wav->ignore_length) {
GST_DEBUG_OBJECT (wav, "Ignoring length");
size = 0;
}
if (wav->streaming) {
gst_adapter_flush (wav->adapter, 8);
gotdata = TRUE;
@ -1323,7 +1337,7 @@ gst_wavparse_stream_headers (GstWavParse * wav)
/* We will continue parsing tags 'till end */
wav->offset += size;
}
GST_DEBUG_OBJECT (wav, "datasize = %d", size);
GST_DEBUG_OBJECT (wav, "datasize = %u", size);
break;
}
case GST_RIFF_TAG_fact:{
@ -1337,7 +1351,7 @@ gst_wavparse_stream_headers (GstWavParse * wav)
/* need more data */
goto exit;
}
GST_DEBUG_OBJECT (wav, "need %d, available %d; ignoring chunk",
GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk",
data_size, size);
break;
}
@ -1385,7 +1399,7 @@ gst_wavparse_stream_headers (GstWavParse * wav)
/* need more data */
goto exit;
}
GST_DEBUG_OBJECT (wav, "need %d, available %d; ignoring chunk",
GST_DEBUG_OBJECT (wav, "need %u, available %u; ignoring chunk",
data_size, size);
break;
}
@ -1520,18 +1534,20 @@ gst_wavparse_stream_headers (GstWavParse * wav)
wav->bps =
(guint32) gst_util_uint64_scale ((guint64) wav->rate, wav->datasize,
(guint64) wav->fact);
GST_INFO_OBJECT (wav, "calculated bps : %d, enabling VBR", wav->bps);
GST_INFO_OBJECT (wav, "calculated bps : %u, enabling VBR", wav->bps);
#endif
wav->vbr = TRUE;
}
if (gst_wavparse_calculate_duration (wav)) {
gst_segment_init (&wav->segment, GST_FORMAT_TIME);
wav->segment.duration = wav->duration;
if (!wav->ignore_length)
wav->segment.duration = wav->duration;
} else {
/* no bitrate, let downstream peer do the math, we'll feed it bytes. */
gst_segment_init (&wav->segment, GST_FORMAT_BYTES);
wav->segment.duration = wav->datasize;
if (!wav->ignore_length)
wav->segment.duration = wav->datasize;
}
/* now we have all the info to perform a pending seek if any, if no
@ -1558,7 +1574,7 @@ gst_wavparse_stream_headers (GstWavParse * wav)
if (wav->blockalign > 0)
wav->max_buf_size -= (wav->max_buf_size % wav->blockalign);
GST_DEBUG_OBJECT (wav, "max buffer size %d", wav->max_buf_size);
GST_DEBUG_OBJECT (wav, "max buffer size %u", wav->max_buf_size);
return GST_FLOW_OK;
@ -1607,7 +1623,7 @@ invalid_blockalign:
{
GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL),
("Stream claims blockalign = %u, which is more than %u - invalid data",
wav->blockalign, wav->channels * (guint) ceil (wav->depth / 8.0)));
wav->blockalign, wav->channels * ((wav->depth + 7) / 8)));
goto fail;
}
invalid_bps:
@ -1626,7 +1642,7 @@ no_bytes_per_sample:
unknown_format:
{
GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL),
("No caps found for format 0x%x, %d channels, %d Hz",
("No caps found for format 0x%x, %u channels, %u Hz",
wav->format, wav->channels, wav->rate));
goto fail;
}
@ -1818,13 +1834,13 @@ iterate_adapter:
if (G_UNLIKELY (extra)) {
extra = wav->bytes_per_sample - extra;
if (extra <= avail) {
GST_DEBUG_OBJECT (wav, "flushing %d bytes to sample boundary", extra);
GST_DEBUG_OBJECT (wav, "flushing %u bytes to sample boundary", extra);
gst_adapter_flush (wav->adapter, extra);
wav->offset += extra;
wav->dataleft -= extra;
goto iterate_adapter;
} else {
GST_DEBUG_OBJECT (wav, "flushing %d bytes", avail);
GST_DEBUG_OBJECT (wav, "flushing %u bytes", avail);
gst_adapter_clear (wav->adapter);
wav->offset += avail;
wav->dataleft -= avail;
@ -1833,7 +1849,7 @@ iterate_adapter:
}
if (avail < desired) {
GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail);
GST_LOG_OBJECT (wav, "Got only %u bytes of data from the sinkpad", avail);
return GST_FLOW_OK;
}
@ -1885,9 +1901,10 @@ iterate_adapter:
if (wav->bps > 0) {
/* and timestamps if we have a bitrate, be careful for overflows */
timestamp = uint64_ceiling_scale (pos, GST_SECOND, (guint64) wav->bps);
timestamp =
gst_util_uint64_scale_ceil (pos, GST_SECOND, (guint64) wav->bps);
next_timestamp =
uint64_ceiling_scale (nextpos, GST_SECOND, (guint64) wav->bps);
gst_util_uint64_scale_ceil (nextpos, GST_SECOND, (guint64) wav->bps);
duration = next_timestamp - timestamp;
/* update current running segment position */
@ -1897,8 +1914,8 @@ iterate_adapter:
guint64 bps =
gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact);
/* and timestamps if we have a bitrate, be careful for overflows */
timestamp = uint64_ceiling_scale (pos, GST_SECOND, bps);
next_timestamp = uint64_ceiling_scale (nextpos, GST_SECOND, bps);
timestamp = gst_util_uint64_scale_ceil (pos, GST_SECOND, bps);
next_timestamp = gst_util_uint64_scale_ceil (nextpos, GST_SECOND, bps);
duration = next_timestamp - timestamp;
} else {
/* no bitrate, all we know is that the first sample has timestamp 0, all
@ -2191,10 +2208,12 @@ gst_wavparse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
if (bps) {
if (start >= 0)
start =
uint64_ceiling_scale (start, GST_SECOND, (guint64) wav->bps);
gst_util_uint64_scale_ceil (start, GST_SECOND,
(guint64) wav->bps);
if (stop >= 0)
stop =
uint64_ceiling_scale (stop, GST_SECOND, (guint64) wav->bps);
gst_util_uint64_scale_ceil (stop, GST_SECOND,
(guint64) wav->bps);
}
}
} else {
@ -2319,13 +2338,14 @@ gst_wavparse_pad_convert (GstPad * pad,
"src=%" G_GINT64_FORMAT ", offset=%" G_GINT64_FORMAT, src_value,
wavparse->offset);
if (wavparse->bps > 0)
*dest_value = uint64_ceiling_scale (src_value, GST_SECOND,
*dest_value = gst_util_uint64_scale_ceil (src_value, GST_SECOND,
(guint64) wavparse->bps);
else if (wavparse->fact) {
guint64 bps = uint64_ceiling_scale_int (wavparse->datasize,
guint64 bps = gst_util_uint64_scale_int_ceil (wavparse->datasize,
wavparse->rate, wavparse->fact);
*dest_value = uint64_ceiling_scale_int (src_value, GST_SECOND, bps);
*dest_value =
gst_util_uint64_scale_int_ceil (src_value, GST_SECOND, bps);
} else {
res = FALSE;
}
@ -2438,6 +2458,11 @@ gst_wavparse_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
gint64 duration = 0;
GstFormat format;
if (wav->ignore_length) {
res = FALSE;
break;
}
gst_query_parse_duration (query, &format, NULL);
switch (format) {
@ -2626,6 +2651,43 @@ gst_wavparse_change_state (GstElement * element, GstStateChange transition)
return ret;
}
static void
gst_wavparse_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstWavParse *self;
g_return_if_fail (GST_IS_WAVPARSE (object));
self = GST_WAVPARSE (object);
switch (prop_id) {
case PROP_IGNORE_LENGTH:
self->ignore_length = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
}
}
static void
gst_wavparse_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstWavParse *self;
g_return_if_fail (GST_IS_WAVPARSE (object));
self = GST_WAVPARSE (object);
switch (prop_id) {
case PROP_IGNORE_LENGTH:
g_value_set_boolean (value, self->ignore_length);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{

View file

@ -116,6 +116,8 @@ struct _GstWavParse {
gboolean first;
/* discont after seek */
gboolean discont;
gboolean ignore_length;
};
struct _GstWavParseClass {

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 mt nb nl or pl pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_HK zh_TW
af az bg ca cs da de el en_GB eo es eu fi fr gl hu id it ja lt lv mt nb nl or pl pt_BR ro ru sk sl sq sr sv tr uk vi zh_CN zh_HK zh_TW

832
po/eo.po Normal file
View file

@ -0,0 +1,832 @@
# Esperanto translation for gst-plugins-good.
# Copyright (C) 2011 Free Software Foundation, Inc.
# This file is distributed under the same license as the gst-plugins-good package.
# Kristjan SCHMIDT <kristjan.schmidt@googlemail.com>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: gst-plugins-good 0.10.28.2\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n"
"POT-Creation-Date: 2011-04-16 16:25+0100\n"
"PO-Revision-Date: 2011-06-04 21:48+0100\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"
#: ext/esd/esdsink.c:253 ext/esd/esdsink.c:358
msgid "Could not establish connection to sound server"
msgstr ""
#: ext/esd/esdsink.c:260
msgid "Failed to query sound server capabilities"
msgstr ""
#. TRANSLATORS: 'song title' by 'artist name'
#: ext/pulse/pulsesink.c:2686
#, c-format
msgid "'%s' by '%s'"
msgstr "'%s' de '%s'"
#: ext/flac/gstflacdec.c:1117 ext/libpng/gstpngdec.c:349
#: ext/libpng/gstpngdec.c:360 ext/libpng/gstpngdec.c:559
#: ext/wavpack/gstwavpackparse.c:1170 gst/avi/gstavidemux.c:5203
msgid "Internal data stream error."
msgstr "Interna datumflu-eraro."
#: ext/jpeg/gstjpegdec.c:286
msgid "Failed to decode JPEG image"
msgstr ""
#: ext/shout2/gstshout2.c:578
msgid "Could not connect to server"
msgstr "Ne eblis konekti al servilo"
#: ext/soup/gstsouphttpsrc.c:871
msgid "Server does not support seeking."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1078
msgid "Could not resolve server name."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1084
msgid "Could not establish connection to server."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1089
msgid "Secure connection setup failed."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1094
msgid "A network error occured, or the server closed the connection unexpectedly."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1100
msgid "Server sent bad data."
msgstr ""
#: ext/soup/gstsouphttpsrc.c:1249
msgid "No URL set."
msgstr ""
#: gst/avi/gstavimux.c:1810
msgid "No or invalid input audio, AVI stream will be corrupt."
msgstr ""
#: gst/quicktime/qtdemux.c:519 gst/quicktime/qtdemux.c:523
msgid "This file contains no playable streams."
msgstr ""
#: gst/quicktime/qtdemux.c:558 gst/quicktime/qtdemux.c:4009
#: gst/quicktime/qtdemux.c:4071 gst/quicktime/qtdemux.c:4219
msgid "This file is invalid and cannot be played."
msgstr ""
#: gst/quicktime/qtdemux.c:2439 gst/quicktime/qtdemux.c:2515
#: gst/quicktime/qtdemux.c:2558 gst/quicktime/qtdemux.c:4798
#: gst/quicktime/qtdemux.c:4805 gst/quicktime/qtdemux.c:5391
#: gst/quicktime/qtdemux.c:5817 gst/quicktime/qtdemux.c:5824
#: gst/quicktime/qtdemux.c:7305
msgid "This file is corrupt and cannot be played."
msgstr ""
#: gst/quicktime/qtdemux.c:2647
msgid "Invalid atom size."
msgstr ""
#: gst/quicktime/qtdemux.c:2716
msgid "This file is incomplete and cannot be played."
msgstr ""
#: gst/quicktime/qtdemux.c:4994
msgid "The video in this file might not play correctly."
msgstr ""
#: gst/quicktime/qtdemux.c:7334
#, c-format
msgid "This file contains too many streams. Only playing first %d"
msgstr ""
#: gst/rtsp/gstrtspsrc.c:5187
msgid "No supported stream was found. You might need to install a GStreamer RTSP extension plugin for Real media streams."
msgstr ""
#: gst/rtsp/gstrtspsrc.c:5192
msgid "No supported stream was found. You might need to allow more transport protocols or may otherwise be missing the right GStreamer RTSP extension plugin."
msgstr ""
#: gst/wavparse/gstwavparse.c:2103
msgid "Internal data flow error."
msgstr ""
#: sys/oss/gstossmixertrack.c:98 sys/oss4/oss4-mixer.c:722
#: sys/sunaudio/gstsunaudiomixertrack.c:69
msgid "Volume"
msgstr "Laŭteco"
#: sys/oss/gstossmixertrack.c:99 sys/oss4/oss4-mixer.c:735
msgid "Bass"
msgstr "Baso"
#: sys/oss/gstossmixertrack.c:100 sys/oss4/oss4-mixer.c:736
msgid "Treble"
msgstr ""
#: sys/oss/gstossmixertrack.c:101
msgid "Synth"
msgstr "Sintezilo"
#: sys/oss/gstossmixertrack.c:102 sys/oss4/oss4-mixer.c:750
msgid "PCM"
msgstr ""
#: sys/oss/gstossmixertrack.c:103
msgid "Speaker"
msgstr "Parolilo"
#: sys/oss/gstossmixertrack.c:104
msgid "Line-in"
msgstr ""
#: sys/oss/gstossmixertrack.c:105 sys/oss4/oss4-mixer.c:741
msgid "Microphone"
msgstr "Mikrofono"
#: sys/oss/gstossmixertrack.c:106
msgid "CD"
msgstr "KD"
#: sys/oss/gstossmixertrack.c:107
msgid "Mixer"
msgstr "Miksilo"
#: sys/oss/gstossmixertrack.c:108
msgid "PCM-2"
msgstr ""
#: sys/oss/gstossmixertrack.c:109
msgid "Record"
msgstr "Registri"
#: sys/oss/gstossmixertrack.c:110
msgid "In-gain"
msgstr ""
#: sys/oss/gstossmixertrack.c:111
msgid "Out-gain"
msgstr ""
#: sys/oss/gstossmixertrack.c:112
msgid "Line-1"
msgstr ""
#: sys/oss/gstossmixertrack.c:113
msgid "Line-2"
msgstr ""
#: sys/oss/gstossmixertrack.c:114
msgid "Line-3"
msgstr ""
#: sys/oss/gstossmixertrack.c:115
msgid "Digital-1"
msgstr ""
#: sys/oss/gstossmixertrack.c:116
msgid "Digital-2"
msgstr ""
#: sys/oss/gstossmixertrack.c:117
msgid "Digital-3"
msgstr ""
#: sys/oss/gstossmixertrack.c:118
msgid "Phone-in"
msgstr ""
#: sys/oss/gstossmixertrack.c:119
msgid "Phone-out"
msgstr ""
#: sys/oss/gstossmixertrack.c:120
msgid "Video"
msgstr "Video"
#: sys/oss/gstossmixertrack.c:121
msgid "Radio"
msgstr "Radio"
#: sys/oss/gstossmixertrack.c:122 sys/oss4/oss4-mixer.c:764
#: sys/sunaudio/gstsunaudiomixertrack.c:71
msgid "Monitor"
msgstr "Ekrano"
#: sys/oss/gstosssink.c:399 sys/oss4/oss4-sink.c:494
#: sys/oss4/oss4-source.c:361
msgid "Could not open audio device for playback. Device is being used by another application."
msgstr "Ne eblis malfermi la sonaparaton por reproduktado. Ĝi estas uzate de alia aplikaĵo."
#: sys/oss/gstosssink.c:406 sys/oss4/oss4-sink.c:504
#: sys/oss4/oss4-source.c:371
msgid "Could not open audio device for playback. You don't have permission to open the device."
msgstr ""
#: sys/oss/gstosssink.c:414 sys/oss4/oss4-sink.c:515
#: sys/oss4/oss4-source.c:382
msgid "Could not open audio device for playback."
msgstr "Ne eblis malfermi la sonaparaton por reproduktado."
#: sys/oss/gstosssrc.c:370
msgid "Could not open audio device for recording. You don't have permission to open the device."
msgstr ""
#: sys/oss/gstosssrc.c:378
msgid "Could not open audio device for recording."
msgstr "Ne eblis malfermi sonaparaton por registrado."
#: sys/oss4/oss4-mixer.c:302
msgid "Could not open audio device for mixer control handling."
msgstr ""
#: sys/oss4/oss4-mixer.c:316
msgid "Could not open audio device for mixer control handling. This version of the Open Sound System is not supported by this element."
msgstr ""
#: sys/oss4/oss4-mixer.c:723
msgid "Master"
msgstr "Ĉefe"
#: sys/oss4/oss4-mixer.c:724
msgid "Front"
msgstr "Antaŭe"
#: sys/oss4/oss4-mixer.c:725
msgid "Rear"
msgstr "Malantaŭe"
#: sys/oss4/oss4-mixer.c:726
msgid "Headphones"
msgstr "Kaptelefono"
#: sys/oss4/oss4-mixer.c:727
msgid "Center"
msgstr "Centre"
#: sys/oss4/oss4-mixer.c:728
msgid "LFE"
msgstr ""
#: sys/oss4/oss4-mixer.c:729
msgid "Surround"
msgstr "Ĉirkaŭe"
#: sys/oss4/oss4-mixer.c:730
msgid "Side"
msgstr "Flanke"
#: sys/oss4/oss4-mixer.c:731 sys/sunaudio/gstsunaudiomixertrack.c:72
msgid "Built-in Speaker"
msgstr ""
#: sys/oss4/oss4-mixer.c:732 sys/sunaudio/gstsunaudiomixertrack.c:76
msgid "AUX 1 Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:733 sys/sunaudio/gstsunaudiomixertrack.c:77
msgid "AUX 2 Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:734
msgid "AUX Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:737
msgid "3D Depth"
msgstr ""
#: sys/oss4/oss4-mixer.c:738
msgid "3D Center"
msgstr ""
#: sys/oss4/oss4-mixer.c:739
msgid "3D Enhance"
msgstr ""
#: sys/oss4/oss4-mixer.c:740
msgid "Telephone"
msgstr ""
#: sys/oss4/oss4-mixer.c:742 sys/sunaudio/gstsunaudiomixertrack.c:74
msgid "Line Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:743 sys/oss4/oss4-mixer.c:744
msgid "Line In"
msgstr ""
#: sys/oss4/oss4-mixer.c:745
msgid "Internal CD"
msgstr ""
#: sys/oss4/oss4-mixer.c:746
msgid "Video In"
msgstr ""
#: sys/oss4/oss4-mixer.c:747
msgid "AUX 1 In"
msgstr ""
#: sys/oss4/oss4-mixer.c:748
msgid "AUX 2 In"
msgstr ""
#: sys/oss4/oss4-mixer.c:749
msgid "AUX In"
msgstr ""
#: sys/oss4/oss4-mixer.c:751 sys/oss4/oss4-mixer.c:752
msgid "Record Gain"
msgstr ""
#: sys/oss4/oss4-mixer.c:753
msgid "Output Gain"
msgstr ""
#: sys/oss4/oss4-mixer.c:754
msgid "Microphone Boost"
msgstr ""
#: sys/oss4/oss4-mixer.c:755
msgid "Loopback"
msgstr ""
#: sys/oss4/oss4-mixer.c:756
msgid "Diagnostic"
msgstr ""
#: sys/oss4/oss4-mixer.c:757
msgid "Bass Boost"
msgstr ""
#: sys/oss4/oss4-mixer.c:758
msgid "Playback Ports"
msgstr ""
#: sys/oss4/oss4-mixer.c:759
msgid "Input"
msgstr "Enigo"
#: sys/oss4/oss4-mixer.c:760 sys/oss4/oss4-mixer.c:761
msgid "Record Source"
msgstr ""
#: sys/oss4/oss4-mixer.c:762
msgid "Monitor Source"
msgstr ""
#: sys/oss4/oss4-mixer.c:763
msgid "Keyboard Beep"
msgstr ""
#: sys/oss4/oss4-mixer.c:765
msgid "Simulate Stereo"
msgstr ""
#: sys/oss4/oss4-mixer.c:766 sys/oss4/oss4-mixer.c:786
msgid "Stereo"
msgstr "Dukanale"
#: sys/oss4/oss4-mixer.c:767
msgid "Surround Sound"
msgstr "Ĉirkaŭa sono"
#: sys/oss4/oss4-mixer.c:768
msgid "Microphone Gain"
msgstr ""
#: sys/oss4/oss4-mixer.c:769
msgid "Speaker Source"
msgstr ""
#: sys/oss4/oss4-mixer.c:770
msgid "Microphone Source"
msgstr ""
#: sys/oss4/oss4-mixer.c:771
msgid "Jack"
msgstr ""
#: sys/oss4/oss4-mixer.c:772
msgid "Center / LFE"
msgstr ""
#: sys/oss4/oss4-mixer.c:773
msgid "Stereo Mix"
msgstr ""
#: sys/oss4/oss4-mixer.c:774
msgid "Mono Mix"
msgstr ""
#: sys/oss4/oss4-mixer.c:775
msgid "Input Mix"
msgstr ""
#: sys/oss4/oss4-mixer.c:776
msgid "SPDIF In"
msgstr ""
#: sys/oss4/oss4-mixer.c:777 sys/sunaudio/gstsunaudiomixertrack.c:75
msgid "SPDIF Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:778
msgid "Microphone 1"
msgstr "Mikrofono 1"
#: sys/oss4/oss4-mixer.c:779
msgid "Microphone 2"
msgstr "Mikrofono 2"
#: sys/oss4/oss4-mixer.c:780
msgid "Digital Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:781
msgid "Digital In"
msgstr ""
#: sys/oss4/oss4-mixer.c:782
msgid "HDMI"
msgstr ""
#: sys/oss4/oss4-mixer.c:783
msgid "Modem"
msgstr "Modemo"
#: sys/oss4/oss4-mixer.c:784
msgid "Handset"
msgstr ""
#: sys/oss4/oss4-mixer.c:785
msgid "Other"
msgstr "Alia"
#: sys/oss4/oss4-mixer.c:787
msgid "None"
msgstr "Neniu"
#: sys/oss4/oss4-mixer.c:788
msgid "On"
msgstr "Enŝaltite"
#: sys/oss4/oss4-mixer.c:789
msgid "Off"
msgstr "Elŝaltite"
#: sys/oss4/oss4-mixer.c:790
msgid "Mute"
msgstr "Silentigi"
#: sys/oss4/oss4-mixer.c:791
msgid "Fast"
msgstr "Rapide"
#. TRANSLATORS: "Very Low" is a quality setting here
#: sys/oss4/oss4-mixer.c:793
msgid "Very Low"
msgstr "Tre malalte"
#. TRANSLATORS: "Low" is a quality setting here
#: sys/oss4/oss4-mixer.c:795
msgid "Low"
msgstr "Malalte"
#. TRANSLATORS: "Medium" is a quality setting here
#: sys/oss4/oss4-mixer.c:797
msgid "Medium"
msgstr "Meze"
#. TRANSLATORS: "High" is a quality setting here
#: sys/oss4/oss4-mixer.c:799
msgid "High"
msgstr "Alte"
#. TRANSLATORS: "Very High" is a quality setting here
#: sys/oss4/oss4-mixer.c:801 sys/oss4/oss4-mixer.c:802
msgid "Very High"
msgstr "Tre alte"
#. TRANSLATORS: "Production" is a quality setting here
#: sys/oss4/oss4-mixer.c:804
msgid "Production"
msgstr ""
#: sys/oss4/oss4-mixer.c:805
msgid "Front Panel Microphone"
msgstr ""
#: sys/oss4/oss4-mixer.c:806
msgid "Front Panel Line In"
msgstr ""
#: sys/oss4/oss4-mixer.c:807
msgid "Front Panel Headphones"
msgstr ""
#: sys/oss4/oss4-mixer.c:808
msgid "Front Panel Line Out"
msgstr ""
#: sys/oss4/oss4-mixer.c:809
msgid "Green Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:810
msgid "Pink Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:811
msgid "Blue Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:812
msgid "White Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:813
msgid "Black Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:814
msgid "Gray Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:815
msgid "Orange Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:816
msgid "Red Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:817
msgid "Yellow Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:818
msgid "Green Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:819
msgid "Pink Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:820
msgid "Blue Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:821
msgid "White Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:822
msgid "Black Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:823
msgid "Gray Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:824
msgid "Orange Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:825
msgid "Red Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:826
msgid "Yellow Front Panel Connector"
msgstr ""
#: sys/oss4/oss4-mixer.c:827
msgid "Spread Output"
msgstr ""
#: sys/oss4/oss4-mixer.c:828
msgid "Downmix"
msgstr ""
#: sys/oss4/oss4-mixer.c:872
msgid "Virtual Mixer Input"
msgstr ""
#: sys/oss4/oss4-mixer.c:874
msgid "Virtual Mixer Output"
msgstr ""
#: sys/oss4/oss4-mixer.c:876
msgid "Virtual Mixer Channels"
msgstr ""
#. TRANSLATORS: name + number of a volume mixer control
#: sys/oss4/oss4-mixer.c:927
#, c-format
msgid "%s %d Function"
msgstr "%s %d funkcio"
#. TRANSLATORS: name of a volume mixer control
#: sys/oss4/oss4-mixer.c:934
#, c-format
msgid "%s Function"
msgstr "%s funcio"
#: sys/oss4/oss4-sink.c:524 sys/oss4/oss4-source.c:392
msgid "Could not open audio device for playback. This version of the Open Sound System is not supported by this element."
msgstr ""
#: sys/oss4/oss4-sink.c:640
msgid "Playback is not supported by this audio device."
msgstr ""
#: sys/oss4/oss4-sink.c:647
msgid "Audio playback error."
msgstr ""
#: sys/oss4/oss4-source.c:514
msgid "Recording is not supported by this audio device."
msgstr ""
#: sys/oss4/oss4-source.c:521
msgid "Error recording from audio device."
msgstr ""
#: sys/sunaudio/gstsunaudiomixertrack.c:70
msgid "Gain"
msgstr ""
#: sys/sunaudio/gstsunaudiomixertrack.c:73
msgid "Headphone"
msgstr ""
#: sys/v4l2/gstv4l2src.c:887
#, c-format
msgid "Error reading %d bytes from device '%s'."
msgstr ""
#: sys/v4l2/gstv4l2src.c:913
#, c-format
msgid "Got unexpected frame size of %u instead of %u."
msgstr ""
#: sys/v4l2/gstv4l2src.c:931
#, c-format
msgid "Error reading %d bytes on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:99
#, c-format
msgid "Error getting capabilities for device '%s': It isn't a v4l2 driver. Check if it is a v4l1 driver."
msgstr ""
#: sys/v4l2/v4l2_calls.c:139
#, c-format
msgid "Failed to query attributes of input %d in device %s"
msgstr ""
#: sys/v4l2/v4l2_calls.c:169
#, c-format
msgid "Failed to get setting of tuner %d on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:213
#, c-format
msgid "Failed to query norm on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:264 sys/v4l2/v4l2_calls.c:347
#, c-format
msgid "Failed getting controls attributes on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:492
#, c-format
msgid "Cannot identify device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:499
#, c-format
msgid "This isn't a device '%s'."
msgstr "Tio ne estas '%s'-aparato."
#: sys/v4l2/v4l2_calls.c:506
#, c-format
msgid "Could not open device '%s' for reading and writing."
msgstr ""
#: sys/v4l2/v4l2_calls.c:513
#, c-format
msgid "Device '%s' is not a capture device."
msgstr ""
#: sys/v4l2/v4l2_calls.c:522
#, c-format
msgid "Device '%s' is not a output device."
msgstr ""
#: sys/v4l2/v4l2_calls.c:622
#, c-format
msgid "Failed to set norm for device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:660
#, c-format
msgid "Failed to get current tuner frequency for device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:702
#, c-format
msgid "Failed to set current tuner frequency for device '%s' to %lu Hz."
msgstr ""
#: sys/v4l2/v4l2_calls.c:736
#, c-format
msgid "Failed to get signal strength for device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:772
#, c-format
msgid "Failed to get value for control %d on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:807
#, c-format
msgid "Failed to set value %d for control %d on device '%s'."
msgstr ""
#: sys/v4l2/v4l2_calls.c:839
#, c-format
msgid "Failed to get current input on device '%s'. May be it is a radio device"
msgstr ""
#: sys/v4l2/v4l2_calls.c:864
#, c-format
msgid "Failed to set input %d on device %s."
msgstr ""
#: sys/v4l2/v4l2_calls.c:896
#, c-format
msgid "Failed to get current output on device '%s'. May be it is a radio device"
msgstr ""
#: sys/v4l2/v4l2_calls.c:921
#, c-format
msgid "Failed to set output %d on device %s."
msgstr ""
#: sys/v4l2/v4l2src_calls.c:81
#, c-format
msgid "Could not enqueue buffers in device '%s'."
msgstr ""
#: sys/v4l2/v4l2src_calls.c:197
#, c-format
msgid "Failed trying to get video frames from device '%s'."
msgstr ""
#: sys/v4l2/v4l2src_calls.c:199
#, c-format
msgid "Failed after %d tries. device %s. system error: %s"
msgstr ""
#: sys/v4l2/v4l2src_calls.c:239
#, c-format
msgid "Could not get parameters on device '%s'"
msgstr ""
#: sys/v4l2/v4l2src_calls.c:267
msgid "Video input device did not accept new frame rate setting."
msgstr ""
#: sys/v4l2/v4l2src_calls.c:339
#, c-format
msgid "Could not map buffers from device '%s'"
msgstr ""
#: sys/v4l2/v4l2src_calls.c:347
#, c-format
msgid "The driver of device '%s' does not support any known capture method."
msgstr ""
#: sys/ximage/gstximagesrc.c:719
msgid "Changing resolution at runtime is not yet supported."
msgstr ""
#: sys/ximage/gstximagesrc.c:733
msgid "Cannot operate without a clock"
msgstr ""

View file

@ -23,6 +23,12 @@ else
DIRECTSOUND_DIR=
endif
if USE_WAVEFORM
WAVEFORM_DIR=waveform
else
WAVEFORM_DIR=
endif
if USE_SUNAUDIO
SUNAUDIO_DIR=sunaudio
else
@ -77,7 +83,7 @@ else
XIMAGE_DIR=
endif
SUBDIRS=$(DIRECTSOUND_DIR) $(OSS_DIR) $(OSS4_DIR) $(OSX_AUDIO_DIR) $(OSX_VIDEO_DIR) $(SUNAUDIO_DIR) $(V4L2_DIR) $(XIMAGE_DIR)
SUBDIRS=$(DIRECTSOUND_DIR) $(WAVEFORM_DIR) $(OSS_DIR) $(OSS4_DIR) $(OSX_AUDIO_DIR) $(OSX_VIDEO_DIR) $(SUNAUDIO_DIR) $(V4L2_DIR) $(XIMAGE_DIR)
DIST_SUBDIRS=directsound oss oss4 osxaudio osxvideo sunaudio v4l2 waveform ximage

View file

@ -54,6 +54,7 @@
#include <gst/interfaces/mixer.h>
#include <gst/gst-i18n-plugin.h>
#include "gst/glib-compat-private.h"
#include <glib/gprintf.h>
@ -541,8 +542,13 @@ gst_oss4_mixer_start_watch_task (GstOss4Mixer * mixer)
mixer->watch_cond = g_cond_new ();
mixer->watch_shutdown = FALSE;
#if !GLIB_CHECK_VERSION (2, 31, 0)
mixer->watch_thread = g_thread_create (gst_oss4_mixer_watch_thread,
gst_object_ref (mixer), TRUE, &err);
#else
mixer->watch_thread = g_thread_try_new ("oss4-mixer-thread",
gst_oss4_mixer_watch_thread, gst_object_ref (mixer), &err);
#endif
if (mixer->watch_thread == NULL) {
GST_ERROR_OBJECT (mixer, "Could not create watch thread: %s", err->message);

View file

@ -40,6 +40,7 @@
#include "gstv4l2sink.h"
#include "v4l2_calls.h"
#include "gst/gst-i18n-plugin.h"
#include <gst/glib-compat-private.h>
/* videodev2.h is not versioned and we can't easily check for the presence
* of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define

View file

@ -39,6 +39,7 @@
#include "v4l2_calls.h"
#include "gst/gst-i18n-plugin.h"
#include <gst/glib-compat-private.h>
struct _GstV4l2Xv
{

View file

@ -1,19 +1,15 @@
plugin_LTLIBRARIES = libgstwaveformsink.la
# FIXME: Replace DIRECTSOUND CFLAGS+LIBS with waveform related ones and fix
# the configure.ac + sys/Makefile.am to get this stuff building in MingW
# For now, it's just disted for use in the VS builds.
libgstwaveformsink_la_SOURCES = gstwaveformsink.c gstwaveformplugin.c
libgstwaveformsink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(DIRECTSOUND_CFLAGS)
$(GST_PLUGINS_BASE_CFLAGS)
libgstwaveformsink_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(DIRECTSOUND_LIBS)
libgstwaveformsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS)
-lwinmm
libgstwaveformsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstwaveformsink_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstwaveformsink.h

View file

@ -49,10 +49,6 @@
GST_DEBUG_CATEGORY_STATIC (waveformsink_debug);
static void gst_waveform_sink_base_init (gpointer g_class);
static void gst_waveform_sink_class_init (GstWaveFormSinkClass * klass);
static void gst_waveform_sink_init (GstWaveFormSink * wfsink,
GstWaveFormSinkClass * g_class);
static void gst_waveform_sink_finalise (GObject * object);
static void gst_waveform_sink_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
@ -154,7 +150,7 @@ static void
gst_waveform_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
/* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); */
switch (prop_id) {
default:
@ -167,7 +163,7 @@ static void
gst_waveform_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object);
/* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); */
switch (prop_id) {
default:
@ -348,7 +344,7 @@ gst_waveform_sink_getcaps (GstBaseSink * bsink)
static gboolean
gst_waveform_sink_open (GstAudioSink * asink)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
/* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); */
/* nothing to do here as the device needs to be opened with the format we will use */
@ -448,7 +444,7 @@ gst_waveform_sink_unprepare (GstAudioSink * asink)
static gboolean
gst_waveform_sink_close (GstAudioSink * asink)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
/* GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); */
return TRUE;
}

View file

@ -49,6 +49,8 @@
#include <gst/gst.h>
#include <gst/gst-i18n-plugin.h>
#include "gst/glib-compat-private.h"
GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src);
#define GST_CAT_DEFAULT gst_debug_ximage_src

View file

@ -147,6 +147,7 @@ check_PROGRAMS = \
elements/shapewipe \
elements/spectrum \
elements/udpsink \
elements/udpsrc \
elements/videocrop \
elements/videofilter \
elements/y4menc \
@ -296,6 +297,9 @@ elements_sunaudio_LDADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-@GST_MAJORMINOR@ \
$(LDADD)
elements_udpsrc_CFLAGS = $(AM_CFLAGS) $(GIO_CFLAGS)
elements_udpsrc_LDADD = $(LDADD) $(GIO_LIBS)
elements_videocrop_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(LDADD)
elements_videocrop_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)

View file

@ -53,6 +53,7 @@ souphttpsrc
spectrum
sunaudio
udpsink
udpsrc
videocrop
videofilter
wavpackdec

View file

@ -28,6 +28,8 @@
#include <unistd.h>
#endif
#include <glib/gstdio.h>
#include <gst/check/gstcheck.h>
#include <gst/pbutils/encoding-profile.h>
@ -830,7 +832,12 @@ test_average_bitrate_custom (const gchar * elementname,
(guint) gst_util_uint64_scale_round ((guint64) total_bytes,
(guint64) 8 * GST_SECOND, (guint64) total_duration);
fail_unless (bitrate == expected);
gst_tag_list_free (taglist);
}
/* delete file */
g_unlink (location);
g_free (location);
}
GST_START_TEST (test_average_bitrate)

View file

@ -49,6 +49,8 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS (RG_VOLUME_CAPS_TEMPLATE_STRING)
);
static GstBuffer *test_buffer_new (gfloat value);
/* gstcheck sets up a chain function that appends buffers to a global list.
* This is our equivalent of that for event handling. */
static gboolean
@ -78,6 +80,37 @@ setup_rgvolume (void)
return element;
}
static void
send_newsegment_and_empty_buffer (void)
{
GstBuffer *buf;
GstEvent *ev;
GstSegment segment;
fail_unless (g_list_length (events) == 0);
gst_segment_init (&segment, GST_FORMAT_TIME);
ev = gst_event_new_segment (&segment);
fail_unless (gst_pad_push_event (mysrcpad, ev),
"Pushing newsegment event failed");
buf = test_buffer_new (0.0);
GST_BUFFER_SIZE (buf) = 0;
GST_BUFFER_DURATION (buf) = 0;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf);
fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
fail_unless (g_list_length (events) == 1);
fail_unless (events->data == ev);
gst_mini_object_unref ((GstMiniObject *) events->data);
events = g_list_remove (events, ev);
fail_unless (g_list_length (buffers) == 1);
fail_unless (buffers->data == buf);
gst_mini_object_unref ((GstMiniObject *) buffers->data);
buffers = g_list_remove (buffers, buf);
}
static void
cleanup_rgvolume (GstElement * element)
{
@ -292,6 +325,8 @@ GST_START_TEST (test_events)
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +4.95, GST_TAG_TRACK_PEAK, 0.59463,
@ -340,6 +375,8 @@ GST_START_TEST (test_simple)
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, -3.45, GST_TAG_TRACK_PEAK, 1.0,
@ -380,6 +417,8 @@ GST_START_TEST (test_fallback_gain)
"pre-amp", -6.00, "fallback-gain", -3.00, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +3.5, GST_TAG_TRACK_PEAK, 1.0,
@ -423,6 +462,8 @@ GST_START_TEST (test_fallback_track)
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +2.11, GST_TAG_TRACK_PEAK, 1.0, NULL);
@ -448,6 +489,8 @@ GST_START_TEST (test_fallback_album)
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_ALBUM_GAIN, +3.73, GST_TAG_ALBUM_PEAK, 1.0, NULL);
@ -470,6 +513,8 @@ GST_START_TEST (test_headroom)
"pre-amp", +0.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +3.50, GST_TAG_TRACK_PEAK, 1.0, NULL);
@ -512,6 +557,8 @@ GST_START_TEST (test_reference_level)
"headroom", +0.00, "pre-amp", +0.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
send_newsegment_and_empty_buffer ();
tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, 0.00, GST_TAG_TRACK_PEAK, 0.2,

View file

@ -23,6 +23,8 @@
# include "config.h"
#endif
#include <stdlib.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <libsoup/soup-address.h>
@ -444,8 +446,11 @@ souphttpsrc_suite (void)
TCase *tc_chain, *tc_internet;
g_type_init ();
#if !GLIB_CHECK_VERSION (2, 31, 0)
if (!g_thread_supported ())
g_thread_init (NULL);
#endif
s = suite_create ("souphttpsrc");
tc_chain = tcase_create ("general");
@ -453,7 +458,7 @@ souphttpsrc_suite (void)
suite_add_tcase (s, tc_chain);
run_server (&http_port, &https_port);
g_atexit (stop_server);
atexit (stop_server);
tcase_add_test (tc_chain, test_first_buffer_has_offset);
tcase_add_test (tc_chain, test_redirect_yes);
tcase_add_test (tc_chain, test_redirect_no);

View file

@ -0,0 +1,120 @@
/* GStreamer UDP source unit tests
* Copyright (C) 2011 Tim-Philipp Müller <tim centricular net>
*
* 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.
*/
#include <gst/check/gstcheck.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <unistd.h>
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_START_TEST (test_udpsrc_empty_packet)
{
GstElement *udpsrc;
GSocket *socket;
GstPad *sinkpad;
int port = 0;
udpsrc = gst_check_setup_element ("udpsrc");
fail_unless (udpsrc != NULL);
g_object_set (udpsrc, "port", 0, NULL);
sinkpad = gst_check_setup_sink_pad_by_name (udpsrc, &sinktemplate, "src");
fail_unless (sinkpad != NULL);
gst_pad_set_active (sinkpad, TRUE);
gst_element_set_state (udpsrc, GST_STATE_PLAYING);
g_object_get (udpsrc, "port", &port, NULL);
GST_INFO ("udpsrc port = %d", port);
socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP, NULL);
if (socket != NULL) {
GSocketAddress *sa;
GInetAddress *ia;
gchar *s;
ia = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
s = g_inet_address_to_string (ia);
GST_LOG ("inet address %s", s);
g_free (s);
sa = g_inet_socket_address_new (ia, port);
if (g_socket_send_to (socket, sa, "HeLL0", 0, NULL, NULL) == 0) {
GST_INFO ("sent 0 bytes");
if (g_socket_send_to (socket, sa, "HeLL0", 6, NULL, NULL) == 6) {
GstBuffer *buf;
guint len;
GST_INFO ("sent 6 bytes");
g_usleep (G_USEC_PER_SEC / 2);
len = g_list_length (buffers);
GST_INFO ("%u buffers", len);
fail_unless (len == 1 || len == 2);
/* last buffer should be our HeLL0 string */
buf = GST_BUFFER (g_list_nth_data (buffers, len - 1));
fail_unless_equals_int (GST_BUFFER_SIZE (buf), 6);
fail_unless_equals_string ((gchar *) GST_BUFFER_DATA (buf), "HeLL0");
/* if there's another buffer, it should be 0 bytes */
if (len == 2) {
buf = GST_BUFFER (g_list_nth_data (buffers, 0));
fail_unless_equals_int (GST_BUFFER_SIZE (buf), 0);
}
} else {
GST_WARNING ("send_to(6 bytes) failed");
}
} else {
GST_WARNING ("send_to(0 bytes) failed");
}
g_object_unref (sa);
g_object_unref (ia);
} else {
GST_WARNING ("Could not create IPv4 UDP socket for unit test");
}
gst_element_set_state (udpsrc, GST_STATE_NULL);
gst_check_teardown_pad_by_name (udpsrc, "src");
gst_check_teardown_element (udpsrc);
g_object_unref (socket);
}
GST_END_TEST;
static Suite *
udpsrc_suite (void)
{
Suite *s = suite_create ("udpsrc");
TCase *tc_chain = tcase_create ("udpsrc");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_udpsrc_empty_packet);
return s;
}
GST_CHECK_MAIN (udpsrc)

View file

@ -7,6 +7,7 @@ EXTRA_DIST = \
id3-577468-unsynced-tag.tag \
id3-588148-unsynced-v24.tag \
pcm16sine.flv \
pinknoise-vorbis.mkv \
test-cert.pem \
test-key.pem

View file

@ -179,8 +179,10 @@ main (int argc, char **argv)
GstPad *eq_sinkpad;
gchar *uri;
#if !GLIB_CHECK_VERSION (2, 31, 0)
if (!g_thread_supported ())
g_thread_init (NULL);
#endif
/* command line option parsing */
ctx = g_option_context_new ("FILENAME");

View file

@ -330,8 +330,10 @@ main (int argc, char **argv)
GOptionContext *ctx;
GError *opt_err = NULL;
#if !GLIB_CHECK_VERSION (2, 31, 0)
if (!g_thread_supported ())
g_thread_init (NULL);
#endif
gtk_init (&argc, &argv);

View file

@ -233,8 +233,10 @@ main (int argc, char **argv)
GOptionContext *ctx;
GError *err = NULL;
#if !GLIB_CHECK_VERSION (2, 31, 0)
if (!g_thread_supported ())
g_thread_init (NULL);
#endif
ctx = g_option_context_new ("");
g_option_context_add_main_entries (ctx, options, NULL);

View file

@ -491,7 +491,13 @@ main (int argc, char *argv[])
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
loop = g_main_loop_new (NULL, FALSE);
if (!(input_thread = g_thread_create (read_user, source, TRUE, NULL))) {
#if !GLIB_CHECK_VERSION (2, 31, 0)
input_thread = g_thread_create (read_user, source, TRUE, NULL);
#else
input_thread = g_thread_try_new ("v4l2src-test", read_user, source, NULL);
#endif
if (input_thread == NULL) {
fprintf (stderr, "error: g_thread_create return NULL");
return -1;
}

View file

@ -193,8 +193,10 @@ main (int argc, char **argv)
GstCaps *filter_caps = NULL;
GList *caps_list, *l;
#if !GLIB_CHECK_VERSION (2, 31, 0)
if (!g_thread_supported ())
g_thread_init (NULL);
#endif
/* command line option parsing */
ctx = g_option_context_new ("");