From ad8f694ec6398845e8283aaeaceb953ea116f733 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 11 Nov 2011 10:27:27 +0100 Subject: [PATCH] remove bogus files They got somehow commited in 7012e88090e69339c60a4eb9449f7a7e39ca6aa3 --- gst-libs/gst/audio/gstaudioprocess.c | 224 -- gst-libs/gst/audio/gstaudioprocess.h | 61 - gst-libs/gst/audio/gstaudioringbuffer.c | 216 -- gst-libs/gst/audio/gstaudioringbuffer.h | 98 - gst-libs/gst/audio/gstbaseaudiosrc.c.orig | 1129 ------- gst-libs/gst/audio/gstbaseaudiosrc.c.rej | 127 - gst-libs/gst/audio/gstringbufferthread.c | 362 -- gst-libs/gst/audio/gstringbufferthread.h | 93 - gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch | 617 ---- gst-libs/gst/cdda/gstcddabasesrc.c.orig | 1594 --------- .../gst/rtp/gst-plugins-base-rtcp-feedback.patch | 224 -- gst-libs/gst/rtp/gstbasertppayload.c.orig | 1040 ------ gst-libs/gst/rtp/gstbasertppayload.c.rej | 16 - gst-libs/gst/rtp/gstrtpbuffer.c.new | 1403 -------- gst-libs/gst/rtsp/gstrtspconnection.c.orig | 3519 -------------------- gst-libs/gst/rtsp/rtsp-marshal.c | 85 - gst-libs/gst/rtsp/rtsp-marshal.h | 20 - gst-libs/gst/rtsp/rtspdefs.patch | 73 - gst/videorate/videorate-discont.patch | 48 - 19 files changed, 10949 deletions(-) delete mode 100644 gst-libs/gst/audio/gstaudioprocess.c delete mode 100644 gst-libs/gst/audio/gstaudioprocess.h delete mode 100644 gst-libs/gst/audio/gstaudioringbuffer.c delete mode 100644 gst-libs/gst/audio/gstaudioringbuffer.h delete mode 100644 gst-libs/gst/audio/gstbaseaudiosrc.c.orig delete mode 100644 gst-libs/gst/audio/gstbaseaudiosrc.c.rej delete mode 100644 gst-libs/gst/audio/gstringbufferthread.c delete mode 100644 gst-libs/gst/audio/gstringbufferthread.h delete mode 100644 gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch delete mode 100644 gst-libs/gst/cdda/gstcddabasesrc.c.orig delete mode 100644 gst-libs/gst/rtp/gst-plugins-base-rtcp-feedback.patch delete mode 100644 gst-libs/gst/rtp/gstbasertppayload.c.orig delete mode 100644 gst-libs/gst/rtp/gstbasertppayload.c.rej delete mode 100644 gst-libs/gst/rtp/gstrtpbuffer.c.new delete mode 100644 gst-libs/gst/rtsp/gstrtspconnection.c.orig delete mode 100644 gst-libs/gst/rtsp/rtsp-marshal.c delete mode 100644 gst-libs/gst/rtsp/rtsp-marshal.h delete mode 100644 gst-libs/gst/rtsp/rtspdefs.patch delete mode 100644 gst/videorate/videorate-discont.patch diff --git a/gst-libs/gst/audio/gstaudioprocess.c b/gst-libs/gst/audio/gstaudioprocess.c deleted file mode 100644 index c12cd96..0000000 --- a/gst-libs/gst/audio/gstaudioprocess.c +++ /dev/null @@ -1,224 +0,0 @@ -/* GStreamer RTSP extension - * Copyright (C) 2007 Wim Taymans - * - * gstrtspextension.c: RTSP extension mechanism - * - * 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. - */ - -/** - * SECTION:gstrtspextension - * @short_description: Interface for extending RTSP protocols - * - * - * - * This interface is implemented e.g. by the Windows Media Streaming RTSP - * exentension (rtspwms) and the RealMedia RTSP extension (rtspreal). - * - * - * - * Last reviewed on 2007-07-25 (0.10.14) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstrtsp-marshal.h" -#include "gstrtsp-enumtypes.h" -#include "gstrtspextension.h" - -static void gst_rtsp_extension_iface_init (GstRTSPExtension * iface); - -enum -{ - SIGNAL_SEND, - LAST_SIGNAL -}; - -static guint gst_rtsp_extension_signals[LAST_SIGNAL] = { 0 }; - -GType -gst_rtsp_extension_get_type (void) -{ - static GType gst_rtsp_extension_type = 0; - - if (!gst_rtsp_extension_type) { - static const GTypeInfo gst_rtsp_extension_info = { - sizeof (GstRTSPExtensionInterface), - (GBaseInitFunc) gst_rtsp_extension_iface_init, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - NULL, - }; - - gst_rtsp_extension_type = g_type_register_static (G_TYPE_INTERFACE, - "GstRTSPExtension", &gst_rtsp_extension_info, 0); - } - return gst_rtsp_extension_type; -} - -static void -gst_rtsp_extension_iface_init (GstRTSPExtension * iface) -{ - static gboolean initialized = FALSE; - - if (!initialized) { - gst_rtsp_extension_signals[SIGNAL_SEND] = - g_signal_new ("send", G_TYPE_FROM_CLASS (iface), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPExtensionInterface, - send), NULL, NULL, gst_rtsp_marshal_ENUM__POINTER_POINTER, - GST_TYPE_RTSP_RESULT, 2, G_TYPE_POINTER, G_TYPE_POINTER); - initialized = TRUE; - } -} - -gboolean -gst_rtsp_extension_detect_server (GstRTSPExtension * ext, GstRTSPMessage * resp) -{ - GstRTSPExtensionInterface *iface; - gboolean res = TRUE; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->detect_server) - res = iface->detect_server (ext, resp); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_before_send (GstRTSPExtension * ext, GstRTSPMessage * req) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->before_send) - res = iface->before_send (ext, req); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_after_send (GstRTSPExtension * ext, GstRTSPMessage * req, - GstRTSPMessage * resp) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->after_send) - res = iface->after_send (ext, req, resp); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp, - GstStructure * s) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->parse_sdp) - res = iface->parse_sdp (ext, sdp, s); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_setup_media (GstRTSPExtension * ext, GstSDPMedia * media) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->setup_media) - res = iface->setup_media (ext, media); - - return res; -} - -gboolean -gst_rtsp_extension_configure_stream (GstRTSPExtension * ext, GstCaps * caps) -{ - GstRTSPExtensionInterface *iface; - gboolean res = TRUE; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->configure_stream) - res = iface->configure_stream (ext, caps); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_get_transports (GstRTSPExtension * ext, - GstRTSPLowerTrans protocols, gchar ** transport) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->get_transports) - res = iface->get_transports (ext, protocols, transport); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_OK; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->stream_select) - res = iface->stream_select (ext, url); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_receive_request (GstRTSPExtension * ext, - GstRTSPMessage * msg) -{ - GstRTSPExtensionInterface *iface; - GstRTSPResult res = GST_RTSP_ENOTIMPL; - - iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext); - if (iface->receive_request) - res = iface->receive_request (ext, msg); - - return res; -} - -GstRTSPResult -gst_rtsp_extension_send (GstRTSPExtension * ext, GstRTSPMessage * req, - GstRTSPMessage * resp) -{ - GstRTSPResult res = GST_RTSP_OK; - - g_signal_emit (ext, gst_rtsp_extension_signals[SIGNAL_SEND], 0, - req, resp, &res); - - return res; -} diff --git a/gst-libs/gst/audio/gstaudioprocess.h b/gst-libs/gst/audio/gstaudioprocess.h deleted file mode 100644 index 8cd0157..0000000 --- a/gst-libs/gst/audio/gstaudioprocess.h +++ /dev/null @@ -1,61 +0,0 @@ -/* GStreamer Audio Process - * Copyright (C) 2010 Wim Taymans - * - * gstaudioprocess.h: Audio processing extension - * - * 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 __GST_AUDIO_PROCESS_H__ -#define __GST_AUDIO_PROCESS_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_PROCESS \ - (gst_audio_process_get_type ()) -#define GST_AUDIO_PROCESS(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUDIO_PROCESS, GstAudioProcess)) -#define GST_IS_AUDIO_PROCESS(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUDIO_PROCESS)) -#define GST_AUDIO_PROCESS_GET_INTERFACE(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_AUDIO_PROCESS, GstAudioProcessInterface)) - -typedef struct _GstAudioProcess GstAudioProcess; -typedef struct _GstAudioProcessInterface GstAudioProcessInterface; - -struct _GstAudioProcessInterface { - GTypeInterface parent; - - /* vfunctions */ - gint (*activate) (GstAudioProcess *process, gboolean active); - gint (*process) (GstAudioProcess *process, gpointer src_in, gpointer sink_in, - gpointer src_out, guint length); - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; -}; - -GType gst_audio_process_get_type (void); - -/* invoke vfunction on interface */ -gint gst_audio_process_process (GstAudioProcess *ext, gpointer src_in, gpointer sink_in, - gpointer src_out, guint length); - -G_END_DECLS - -#endif /* __GST_AUDIO_PROCESS_H__ */ diff --git a/gst-libs/gst/audio/gstaudioringbuffer.c b/gst-libs/gst/audio/gstaudioringbuffer.c deleted file mode 100644 index 19e9070..0000000 --- a/gst-libs/gst/audio/gstaudioringbuffer.c +++ /dev/null @@ -1,216 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * gstaudioringbuffer.c: simple audio ringbuffer base class - * - * 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 - -#include "gstaudioringbuffer.h" - -GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug); -#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug - -static void gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass); -static void gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer, - GstAudioRingBufferClass * klass); -static void gst_audio_ring_buffer_dispose (GObject * object); -static void gst_audio_ring_buffer_finalize (GObject * object); - -static GstRingBufferClass *ring_parent_class = NULL; - -static gboolean gst_audio_ring_buffer_start (GstRingBuffer * buf); -static gboolean gst_audio_ring_buffer_pause (GstRingBuffer * buf); -static gboolean gst_audio_ring_buffer_stop (GstRingBuffer * buf); -static gboolean gst_audio_ring_buffer_activate (GstRingBuffer * buf, - gboolean active); - -/* ringbuffer abstract base class */ -GType -gst_audio_ring_buffer_get_type (void) -{ - static GType ringbuffer_type = 0; - - if (!ringbuffer_type) { - static const GTypeInfo ringbuffer_info = { - sizeof (GstAudioRingBufferClass), - NULL, - NULL, - (GClassInitFunc) gst_audio_ring_buffer_class_init, - NULL, - NULL, - sizeof (GstAudioRingBuffer), - 0, - (GInstanceInitFunc) gst_audio_ring_buffer_init, - NULL - }; - - ringbuffer_type = - g_type_register_static (GST_TYPE_RING_BUFFER, "GstAudioSinkRingBuffer", - &ringbuffer_info, G_TYPE_FLAG_ABSTRACT); - - GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "audioringbuffer", 0, - "audio ringbuffer"); - } - return ringbuffer_type; -} - -static void -gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass) -{ - GObjectClass *gobject_class; - GstRingBufferClass *gstringbuffer_class; - - gobject_class = (GObjectClass *) klass; - gstringbuffer_class = (GstRingBufferClass *) klass; - - ring_parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_audio_ring_buffer_dispose; - gobject_class->finalize = gst_audio_ring_buffer_finalize; - - gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start); - gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_pause); - gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start); - gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_stop); - - gstringbuffer_class->activate = - GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_activate); -} - -static void -gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer, - GstAudioRingBufferClass * g_class) -{ -} - -static void -gst_audio_ring_buffer_dispose (GObject * object) -{ - G_OBJECT_CLASS (ring_parent_class)->dispose (object); -} - -static void -gst_audio_ring_buffer_finalize (GObject * object) -{ - G_OBJECT_CLASS (ring_parent_class)->finalize (object); -} - -static gboolean -gst_audio_ring_buffer_activate (GstRingBuffer * buf, gboolean active) -{ - GstAudioRingBuffer *abuf; - gboolean res; - - abuf = GST_AUDIO_RING_BUFFER_CAST (buf); - - GST_OBJECT_UNLOCK (buf); - res = gst_ring_buffer_thread_activate (abuf->thread, active); - GST_OBJECT_LOCK (buf); - - return res; -} - -gboolean -gst_audio_ring_buffer_set_thread (GstAudioRingBuffer * buf, - GstRingBufferThread * thread) -{ - GstRingBufferThread *old; - - g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE); - - old = buf->thread; - if (thread) - gst_object_ref (thread); - buf->thread = thread; - if (old) - gst_object_unref (old); - - if (thread) - gst_ring_buffer_thread_set_ringbuffer (thread, buf); - - return TRUE; -} - -gboolean -gst_audio_ring_buffer_link (GstAudioRingBuffer * buf1, - GstAudioRingBuffer * buf2) -{ - buf1->link = buf2; - buf2->link = buf1; - - return TRUE; -} - -static gboolean -gst_audio_ring_buffer_start (GstRingBuffer * buf) -{ - GstAudioRingBuffer *abuf; - - abuf = GST_AUDIO_RING_BUFFER_CAST (buf); - - GST_DEBUG_OBJECT (buf, "start, sending signal"); - - return gst_ring_buffer_thread_start (abuf->thread); -} - -static gboolean -gst_audio_ring_buffer_pause (GstRingBuffer * buf) -{ - GstAudioRingBuffer *abuf; - GstAudioRingBufferClass *cbuf; - - abuf = GST_AUDIO_RING_BUFFER_CAST (buf); - cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf); - - /* unblock any pending writes to the audio device */ - if (cbuf->reset) { - GST_DEBUG_OBJECT (abuf, "reset..."); - cbuf->reset (abuf); - GST_DEBUG_OBJECT (abuf, "reset done"); - } - return TRUE; -} - -static gboolean -gst_audio_ring_buffer_stop (GstRingBuffer * buf) -{ - GstAudioRingBuffer *abuf; - GstAudioRingBufferClass *cbuf; - - abuf = GST_AUDIO_RING_BUFFER_CAST (buf); - cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf); - - /* unblock any pending writes to the audio device */ - if (cbuf->reset) { - GST_DEBUG_OBJECT (abuf, "reset..."); - cbuf->reset (abuf); - GST_DEBUG_OBJECT (abuf, "reset done"); - } -#if 0 - if (abuf->running) { - GST_DEBUG_OBJECT (sink, "stop, waiting..."); - GST_AUDIO_RING_BUFFER_WAIT (buf); - GST_DEBUG_OBJECT (sink, "stopped"); - } -#endif - - return TRUE; -} diff --git a/gst-libs/gst/audio/gstaudioringbuffer.h b/gst-libs/gst/audio/gstaudioringbuffer.h deleted file mode 100644 index c643e84..0000000 --- a/gst-libs/gst/audio/gstaudioringbuffer.h +++ /dev/null @@ -1,98 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * gstaudioringbuffer.h: - * - * 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 __GST_AUDIO_RING_BUFFER_H__ -#define __GST_AUDIO_RING_BUFFER_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_RING_BUFFER (gst_audio_ring_buffer_get_type()) -#define GST_AUDIO_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBuffer)) -#define GST_AUDIO_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass)) -#define GST_AUDIO_RING_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass)) -#define GST_IS_AUDIO_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_RING_BUFFER)) -#define GST_IS_AUDIO_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_RING_BUFFER)) -#define GST_AUDIO_RING_BUFFER_CAST(obj) ((GstAudioRingBuffer *)obj) - -typedef struct _GstAudioRingBuffer GstAudioRingBuffer; -typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass; - -#include - -typedef enum { - GST_AUDIO_RING_BUFFER_MODE_UNKNOWN, - GST_AUDIO_RING_BUFFER_MODE_PLAYBACK, - GST_AUDIO_RING_BUFFER_MODE_CAPTURE -} GstAudioRingBufferMode; -/** - * GstAudioRingBuffer: - * - * Opaque #GstAudioRingBuffer. - */ -struct _GstAudioRingBuffer { - GstRingBuffer element; - - /*< protected >*/ - GstAudioRingBufferMode mode; - GstRingBufferThread *thread; - - GstAudioRingBuffer *link; - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; -}; - -/** - * GstAudioRingBufferClass: - * @parent_class: the parent class structure. - * @process: Write/Read data to/from the device. - * @reset: Returns as quickly as possible from a write/read and flush any pending - * samples from the device. - * - * #GstAudioRingBuffer class. Override the vmethods to implement functionality. - */ -struct _GstAudioRingBufferClass { - GstRingBufferClass parent_class; - - /* vtable */ - - /* write/read samples to the device */ - gint (*process) (GstAudioRingBuffer *buf, gpointer data, guint length); - /* reset the audio device, unblock from a read/write */ - void (*reset) (GstAudioRingBuffer *buf); - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; -}; - -GType gst_audio_ring_buffer_get_type(void); - -gboolean gst_audio_ring_buffer_link (GstAudioRingBuffer *buf1, GstAudioRingBuffer *buf2); - -gboolean gst_audio_ring_buffer_set_thread (GstAudioRingBuffer *buf, GstRingBufferThread *thread); - -G_END_DECLS - -#endif /* __GST_AUDIO_RING_BUFFER_H__ */ diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c.orig b/gst-libs/gst/audio/gstbaseaudiosrc.c.orig deleted file mode 100644 index 1c2c72c..0000000 --- a/gst-libs/gst/audio/gstbaseaudiosrc.c.orig +++ /dev/null @@ -1,1129 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * gstbaseaudiosrc.c: - * - * 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. - */ - -/** - * SECTION:gstbaseaudiosrc - * @short_description: Base class for audio sources - * @see_also: #GstAudioSrc, #GstRingBuffer. - * - * This is the base class for audio sources. Subclasses need to implement the - * ::create_ringbuffer vmethod. This base class will then take care of - * reading samples from the ringbuffer, synchronisation and flushing. - * - * Last reviewed on 2006-09-27 (0.10.12) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "gstbaseaudiosrc.h" - -#include "gst/gst-i18n-plugin.h" - -GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug); -#define GST_CAT_DEFAULT gst_base_audio_src_debug - -GType -gst_base_audio_src_slave_method_get_type (void) -{ - static GType slave_method_type = 0; - static const GEnumValue slave_method[] = { - {GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE, "Resampling slaving", "resample"}, - {GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP, "Re-timestamp", "re-timestamp"}, - {GST_BASE_AUDIO_SRC_SLAVE_SKEW, "Skew", "skew"}, - {GST_BASE_AUDIO_SRC_SLAVE_NONE, "No slaving", "none"}, - {0, NULL, NULL}, - }; - - if (!slave_method_type) { - slave_method_type = - g_enum_register_static ("GstBaseAudioSrcSlaveMethod", slave_method); - } - return slave_method_type; -} - -#define GST_BASE_AUDIO_SRC_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SRC, GstBaseAudioSrcPrivate)) - -struct _GstBaseAudioSrcPrivate -{ - gboolean provide_clock; - - /* the clock slaving algorithm in use */ - GstBaseAudioSrcSlaveMethod slave_method; -}; - -/* BaseAudioSrc signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -#define DEFAULT_BUFFER_TIME ((200 * GST_MSECOND) / GST_USECOND) -#define DEFAULT_LATENCY_TIME ((10 * GST_MSECOND) / GST_USECOND) -#define DEFAULT_ACTUAL_BUFFER_TIME -1 -#define DEFAULT_ACTUAL_LATENCY_TIME -1 -#define DEFAULT_PROVIDE_CLOCK TRUE -#define DEFAULT_SLAVE_METHOD GST_BASE_AUDIO_SRC_SLAVE_SKEW - -enum -{ - PROP_0, - PROP_BUFFER_TIME, - PROP_LATENCY_TIME, - PROP_ACTUAL_BUFFER_TIME, - PROP_ACTUAL_LATENCY_TIME, - PROP_PROVIDE_CLOCK, - PROP_SLAVE_METHOD, - PROP_LAST -}; - -static void -_do_init (GType type) -{ - GST_DEBUG_CATEGORY_INIT (gst_base_audio_src_debug, "baseaudiosrc", 0, - "baseaudiosrc element"); - -#ifdef ENABLE_NLS - GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, - LOCALEDIR); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif /* ENABLE_NLS */ -} - -GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_base_audio_src, GstPushSrc, - GST_TYPE_PUSH_SRC, _do_init); - -static void gst_base_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_base_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_base_audio_src_dispose (GObject * object); - -static GstStateChangeReturn gst_base_audio_src_change_state (GstElement * - element, GstStateChange transition); - -static GstClock *gst_base_audio_src_provide_clock (GstElement * elem); -static GstClockTime gst_base_audio_src_get_time (GstClock * clock, - GstBaseAudioSrc * src); - -static GstFlowReturn gst_base_audio_src_create (GstBaseSrc * bsrc, - guint64 offset, guint length, GstBuffer ** buf); -static gboolean gst_base_audio_src_check_get_range (GstBaseSrc * bsrc); - -static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event); -static void gst_base_audio_src_get_times (GstBaseSrc * bsrc, - GstBuffer * buffer, GstClockTime * start, GstClockTime * end); -static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps); -static gboolean gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query); -static void gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps); - -/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */ - -static void -gst_base_audio_src_base_init (gpointer g_class) -{ -} - -static void -gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - g_type_class_add_private (klass, sizeof (GstBaseAudioSrcPrivate)); - - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_base_audio_src_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_base_audio_src_get_property); - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose); - - g_object_class_install_property (gobject_class, PROP_BUFFER_TIME, - g_param_spec_int64 ("buffer-time", "Buffer Time", - "Size of audio buffer in microseconds", 1, - G_MAXINT64, DEFAULT_BUFFER_TIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_LATENCY_TIME, - g_param_spec_int64 ("latency-time", "Latency Time", - "Audio latency in microseconds", 1, - G_MAXINT64, DEFAULT_LATENCY_TIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstBaseAudioSrc:actual-buffer-time: - * - * Actual configured size of audio buffer in microseconds. - * - * Since: 0.10.20 - **/ - g_object_class_install_property (gobject_class, PROP_ACTUAL_BUFFER_TIME, - g_param_spec_int64 ("actual-buffer-time", "Actual Buffer Time", - "Actual configured size of audio buffer in microseconds", - DEFAULT_ACTUAL_BUFFER_TIME, G_MAXINT64, DEFAULT_ACTUAL_BUFFER_TIME, - G_PARAM_READABLE)); - - /** - * GstBaseAudioSrc:actual-latency-time: - * - * Actual configured audio latency in microseconds. - * - * Since: 0.10.20 - **/ - g_object_class_install_property (gobject_class, PROP_ACTUAL_LATENCY_TIME, - g_param_spec_int64 ("actual-latency-time", "Actual Latency Time", - "Actual configured audio latency in microseconds", - DEFAULT_ACTUAL_LATENCY_TIME, G_MAXINT64, DEFAULT_ACTUAL_LATENCY_TIME, - G_PARAM_READABLE)); - - g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK, - g_param_spec_boolean ("provide-clock", "Provide Clock", - "Provide a clock to be used as the global pipeline clock", - DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD, - g_param_spec_enum ("slave-method", "Slave Method", - "Algorithm to use to match the rate of the masterclock", - GST_TYPE_BASE_AUDIO_SRC_SLAVE_METHOD, DEFAULT_SLAVE_METHOD, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state); - gstelement_class->provide_clock = - GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock); - - gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_src_setcaps); - gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_src_event); - gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_src_query); - gstbasesrc_class->get_times = - GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times); - gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create); - gstbasesrc_class->check_get_range = - GST_DEBUG_FUNCPTR (gst_base_audio_src_check_get_range); - gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_src_fixate); - - /* ref class from a thread-safe context to work around missing bit of - * thread-safety in GObject */ - g_type_class_ref (GST_TYPE_AUDIO_CLOCK); - g_type_class_ref (GST_TYPE_RING_BUFFER); -} - -static void -gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc, - GstBaseAudioSrcClass * g_class) -{ - baseaudiosrc->priv = GST_BASE_AUDIO_SRC_GET_PRIVATE (baseaudiosrc); - - baseaudiosrc->buffer_time = DEFAULT_BUFFER_TIME; - baseaudiosrc->latency_time = DEFAULT_LATENCY_TIME; - baseaudiosrc->priv->provide_clock = DEFAULT_PROVIDE_CLOCK; - baseaudiosrc->priv->slave_method = DEFAULT_SLAVE_METHOD; - /* reset blocksize we use latency time to calculate a more useful - * value based on negotiated format. */ - GST_BASE_SRC (baseaudiosrc)->blocksize = 0; - - baseaudiosrc->clock = gst_audio_clock_new ("GstAudioSrcClock", - (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time, baseaudiosrc); - - /* we are always a live source */ - gst_base_src_set_live (GST_BASE_SRC (baseaudiosrc), TRUE); - /* we operate in time */ - gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME); -} - -static void -gst_base_audio_src_dispose (GObject * object) -{ - GstBaseAudioSrc *src; - - src = GST_BASE_AUDIO_SRC (object); - - GST_OBJECT_LOCK (src); - if (src->clock) - gst_object_unref (src->clock); - src->clock = NULL; - - if (src->ringbuffer) { - gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer)); - src->ringbuffer = NULL; - } - GST_OBJECT_UNLOCK (src); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static GstClock * -gst_base_audio_src_provide_clock (GstElement * elem) -{ - GstBaseAudioSrc *src; - GstClock *clock; - - src = GST_BASE_AUDIO_SRC (elem); - - /* we have no ringbuffer (must be NULL state) */ - if (src->ringbuffer == NULL) - goto wrong_state; - - if (!gst_ring_buffer_is_acquired (src->ringbuffer)) - goto wrong_state; - - GST_OBJECT_LOCK (src); - if (!src->priv->provide_clock) - goto clock_disabled; - - clock = GST_CLOCK_CAST (gst_object_ref (src->clock)); - GST_OBJECT_UNLOCK (src); - - return clock; - - /* ERRORS */ -wrong_state: - { - GST_DEBUG_OBJECT (src, "ringbuffer not acquired"); - return NULL; - } -clock_disabled: - { - GST_DEBUG_OBJECT (src, "clock provide disabled"); - GST_OBJECT_UNLOCK (src); - return NULL; - } -} - -static GstClockTime -gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src) -{ - guint64 raw, samples; - guint delay; - GstClockTime result; - - if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0)) - return GST_CLOCK_TIME_NONE; - - raw = samples = gst_ring_buffer_samples_done (src->ringbuffer); - - /* the number of samples not yet processed, this is still queued in the - * device (not yet read for capture). */ - delay = gst_ring_buffer_delay (src->ringbuffer); - - samples += delay; - - result = gst_util_uint64_scale_int (samples, GST_SECOND, - src->ringbuffer->spec.rate); - - GST_DEBUG_OBJECT (src, - "processed samples: raw %llu, delay %u, real %llu, time %" - GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result)); - - return result; -} - -static gboolean -gst_base_audio_src_check_get_range (GstBaseSrc * bsrc) -{ - /* we allow limited pull base operation of which the details - * will eventually exposed in an as of yet non-existing query. - * Basically pulling can be done on any number of bytes as long - * as the offset is -1 or sequentially increasing. */ - return TRUE; -} - -/** - * gst_base_audio_src_set_provide_clock: - * @src: a #GstBaseAudioSrc - * @provide: new state - * - * Controls whether @src will provide a clock or not. If @provide is %TRUE, - * gst_element_provide_clock() will return a clock that reflects the datarate - * of @src. If @provide is %FALSE, gst_element_provide_clock() will return NULL. - * - * Since: 0.10.16 - */ -void -gst_base_audio_src_set_provide_clock (GstBaseAudioSrc * src, gboolean provide) -{ - g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src)); - - GST_OBJECT_LOCK (src); - src->priv->provide_clock = provide; - GST_OBJECT_UNLOCK (src); -} - -/** - * gst_base_audio_src_get_provide_clock: - * @src: a #GstBaseAudioSrc - * - * Queries whether @src will provide a clock or not. See also - * gst_base_audio_src_set_provide_clock. - * - * Returns: %TRUE if @src will provide a clock. - * - * Since: 0.10.16 - */ -gboolean -gst_base_audio_src_get_provide_clock (GstBaseAudioSrc * src) -{ - gboolean result; - - g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), FALSE); - - GST_OBJECT_LOCK (src); - result = src->priv->provide_clock; - GST_OBJECT_UNLOCK (src); - - return result; -} - -/** - * gst_base_audio_src_set_slave_method: - * @src: a #GstBaseAudioSrc - * @method: the new slave method - * - * Controls how clock slaving will be performed in @src. - * - * Since: 0.10.20 - */ -void -gst_base_audio_src_set_slave_method (GstBaseAudioSrc * src, - GstBaseAudioSrcSlaveMethod method) -{ - g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src)); - - GST_OBJECT_LOCK (src); - src->priv->slave_method = method; - GST_OBJECT_UNLOCK (src); -} - -/** - * gst_base_audio_src_get_slave_method: - * @src: a #GstBaseAudioSrc - * - * Get the current slave method used by @src. - * - * Returns: The current slave method used by @src. - * - * Since: 0.10.20 - */ -GstBaseAudioSrcSlaveMethod -gst_base_audio_src_get_slave_method (GstBaseAudioSrc * src) -{ - GstBaseAudioSrcSlaveMethod result; - - g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), -1); - - GST_OBJECT_LOCK (src); - result = src->priv->slave_method; - GST_OBJECT_UNLOCK (src); - - return result; -} - -static void -gst_base_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstBaseAudioSrc *src; - - src = GST_BASE_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_BUFFER_TIME: - src->buffer_time = g_value_get_int64 (value); - break; - case PROP_LATENCY_TIME: - src->latency_time = g_value_get_int64 (value); - break; - case PROP_PROVIDE_CLOCK: - gst_base_audio_src_set_provide_clock (src, g_value_get_boolean (value)); - break; - case PROP_SLAVE_METHOD: - gst_base_audio_src_set_slave_method (src, g_value_get_enum (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_base_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstBaseAudioSrc *src; - - src = GST_BASE_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_BUFFER_TIME: - g_value_set_int64 (value, src->buffer_time); - break; - case PROP_LATENCY_TIME: - g_value_set_int64 (value, src->latency_time); - break; - case PROP_ACTUAL_BUFFER_TIME: - GST_OBJECT_LOCK (src); - if (src->ringbuffer && src->ringbuffer->acquired) - g_value_set_int64 (value, src->ringbuffer->spec.buffer_time); - else - g_value_set_int64 (value, DEFAULT_ACTUAL_BUFFER_TIME); - GST_OBJECT_UNLOCK (src); - break; - case PROP_ACTUAL_LATENCY_TIME: - GST_OBJECT_LOCK (src); - if (src->ringbuffer && src->ringbuffer->acquired) - g_value_set_int64 (value, src->ringbuffer->spec.latency_time); - else - g_value_set_int64 (value, DEFAULT_ACTUAL_LATENCY_TIME); - GST_OBJECT_UNLOCK (src); - break; - case PROP_PROVIDE_CLOCK: - g_value_set_boolean (value, gst_base_audio_src_get_provide_clock (src)); - break; - case PROP_SLAVE_METHOD: - g_value_set_enum (value, gst_base_audio_src_get_slave_method (src)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) -{ - GstStructure *s; - gint width, depth; - - s = gst_caps_get_structure (caps, 0); - - /* fields for all formats */ - gst_structure_fixate_field_nearest_int (s, "rate", 44100); - gst_structure_fixate_field_nearest_int (s, "channels", 2); - gst_structure_fixate_field_nearest_int (s, "width", 16); - - /* fields for int */ - if (gst_structure_has_field (s, "depth")) { - gst_structure_get_int (s, "width", &width); - /* round width to nearest multiple of 8 for the depth */ - depth = GST_ROUND_UP_8 (width); - gst_structure_fixate_field_nearest_int (s, "depth", depth); - } - if (gst_structure_has_field (s, "signed")) - gst_structure_fixate_field_boolean (s, "signed", TRUE); - if (gst_structure_has_field (s, "endianness")) - gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER); -} - -static gboolean -gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) -{ - GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); - GstRingBufferSpec *spec; - - spec = &src->ringbuffer->spec; - - spec->buffer_time = src->buffer_time; - spec->latency_time = src->latency_time; - - if (!gst_ring_buffer_parse_caps (spec, caps)) - goto parse_error; - - /* calculate suggested segsize and segtotal */ - spec->segsize = - spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND; - spec->segtotal = spec->buffer_time / spec->latency_time; - - GST_DEBUG ("release old ringbuffer"); - - gst_ring_buffer_release (src->ringbuffer); - - gst_ring_buffer_debug_spec_buff (spec); - - GST_DEBUG ("acquire new ringbuffer"); - - if (!gst_ring_buffer_acquire (src->ringbuffer, spec)) - goto acquire_error; - - /* calculate actual latency and buffer times */ - spec->latency_time = - spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample); - spec->buffer_time = - spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate * - spec->bytes_per_sample); - - gst_ring_buffer_debug_spec_buff (spec); - - g_object_notify (G_OBJECT (src), "actual-buffer-time"); - g_object_notify (G_OBJECT (src), "actual-latency-time"); - - return TRUE; - - /* ERRORS */ -parse_error: - { - GST_DEBUG ("could not parse caps"); - return FALSE; - } -acquire_error: - { - GST_DEBUG ("could not acquire ringbuffer"); - return FALSE; - } -} - -static void -gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer, - GstClockTime * start, GstClockTime * end) -{ - /* no need to sync to a clock here, we schedule the samples based - * on our own clock for the moment. */ - *start = GST_CLOCK_TIME_NONE; - *end = GST_CLOCK_TIME_NONE; -} - -static gboolean -gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query) -{ - GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - GstClockTime min_latency, max_latency; - GstRingBufferSpec *spec; - - if (G_UNLIKELY (src->ringbuffer == NULL - || src->ringbuffer->spec.rate == 0)) - goto done; - - spec = &src->ringbuffer->spec; - - /* we have at least 1 segment of latency */ - min_latency = - gst_util_uint64_scale_int (spec->segsize, GST_SECOND, - spec->rate * spec->bytes_per_sample); - /* we cannot delay more than the buffersize else we lose data */ - max_latency = - gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND, - spec->rate * spec->bytes_per_sample); - - GST_DEBUG_OBJECT (src, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - /* we are always live, the min latency is 1 segment and the max latency is - * the complete buffer of segments. */ - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - res = TRUE; - break; - } - default: - res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); - break; - } -done: - return res; -} - -static gboolean -gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event) -{ - GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); - gboolean res; - - res = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - GST_DEBUG_OBJECT (bsrc, "flush-start"); - gst_ring_buffer_pause (src->ringbuffer); - gst_ring_buffer_clear_all (src->ringbuffer); - break; - case GST_EVENT_FLUSH_STOP: - GST_DEBUG_OBJECT (bsrc, "flush-stop"); - /* always resync on sample after a flush */ - src->next_sample = -1; - gst_ring_buffer_clear_all (src->ringbuffer); - break; - case GST_EVENT_SEEK: - GST_DEBUG_OBJECT (bsrc, "refuse to seek"); - res = FALSE; - break; - default: - GST_DEBUG_OBJECT (bsrc, "dropping event %p", event); - break; - } - return res; -} - -/* get the next offset in the ringbuffer for reading samples. - * If the next sample is too far away, this function will position itself to the - * next most recent sample, creating discontinuity */ -static guint64 -gst_base_audio_src_get_offset (GstBaseAudioSrc * src) -{ - guint64 sample; - gint readseg, segdone, segtotal, sps; - gint diff; - - /* assume we can append to the previous sample */ - sample = src->next_sample; - /* no previous sample, try to read from position 0 */ - if (sample == -1) - sample = 0; - - sps = src->ringbuffer->samples_per_seg; - segtotal = src->ringbuffer->spec.segtotal; - - /* figure out the segment and the offset inside the segment where - * the sample should be read from. */ - readseg = sample / sps; - - /* get the currently processed segment */ - segdone = g_atomic_int_get (&src->ringbuffer->segdone) - - src->ringbuffer->segbase; - - GST_DEBUG_OBJECT (src, "reading from %d, we are at %d", readseg, segdone); - - /* see how far away it is from the read segment, normally segdone (where new - * data is written in the ringbuffer) is bigger than readseg (where we are - * reading). */ - diff = segdone - readseg; - if (diff >= segtotal) { - GST_DEBUG_OBJECT (src, "dropped, align to segment %d", segdone); - /* sample would be dropped, position to next playable position */ - sample = ((guint64) (segdone)) * sps; - } - - return sample; -} - -static GstFlowReturn -gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, - GstBuffer ** outbuf) -{ - GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); - GstBuffer *buf; - guchar *data; - guint samples, total_samples; - guint64 sample; - gint bps; - GstRingBuffer *ringbuffer; - GstRingBufferSpec *spec; - guint read; - GstClockTime timestamp, duration; - GstClock *clock; - - ringbuffer = src->ringbuffer; - spec = &ringbuffer->spec; - - if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer))) - goto wrong_state; - - bps = spec->bytes_per_sample; - - if ((length == 0 && bsrc->blocksize == 0) || length == -1) - /* no length given, use the default segment size */ - length = spec->segsize; - else - /* make sure we round down to an integral number of samples */ - length -= length % bps; - - /* figure out the offset in the ringbuffer */ - if (G_UNLIKELY (offset != -1)) { - sample = offset / bps; - /* if a specific offset was given it must be the next sequential - * offset we expect or we fail for now. */ - if (src->next_sample != -1 && sample != src->next_sample) - goto wrong_offset; - } else { - /* calculate the sequentially next sample we need to read. This can jump and - * create a DISCONT. */ - sample = gst_base_audio_src_get_offset (src); - } - - GST_DEBUG_OBJECT (src, "reading from sample %" G_GUINT64_FORMAT, sample); - - /* get the number of samples to read */ - total_samples = samples = length / bps; - - /* FIXME, using a bufferpool would be nice here */ - buf = gst_buffer_new_and_alloc (length); - data = GST_BUFFER_DATA (buf); - - do { - read = gst_ring_buffer_read (ringbuffer, sample, data, samples); - GST_DEBUG_OBJECT (src, "read %u of %u", read, samples); - /* if we read all, we're done */ - if (read == samples) - break; - - /* else something interrupted us and we wait for playing again. */ - GST_DEBUG_OBJECT (src, "wait playing"); - if (gst_base_src_wait_playing (bsrc) != GST_FLOW_OK) - goto stopped; - - GST_DEBUG_OBJECT (src, "continue playing"); - - /* read next samples */ - sample += read; - samples -= read; - data += read * bps; - } while (TRUE); - - /* mark discontinuity if needed */ - if (G_UNLIKELY (sample != src->next_sample) && src->next_sample != -1) { - GST_WARNING_OBJECT (src, - "create DISCONT of %" G_GUINT64_FORMAT " samples at sample %" - G_GUINT64_FORMAT, sample - src->next_sample, sample); - GST_ELEMENT_WARNING (src, CORE, CLOCK, - (_("Can't record audio fast enough")), - ("Dropped %" G_GUINT64_FORMAT " samples. This is most likely because " - "downstream can't keep up and is consuming samples too slowly.", - sample - src->next_sample)); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - } - - src->next_sample = sample + samples; - - /* get the normal timestamp to get the duration. */ - timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate); - duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND, - spec->rate) - timestamp; - - GST_OBJECT_LOCK (src); - if (!(clock = GST_ELEMENT_CLOCK (src))) - goto no_sync; - - if (clock != src->clock) { - /* we are slaved, check how to handle this */ - switch (src->priv->slave_method) { - case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE: - /* not implemented, use skew algorithm. This algorithm should - * work on the readout pointer and produces more or less samples based - * on the clock drift */ - case GST_BASE_AUDIO_SRC_SLAVE_SKEW: - { - GstClockTime running_time; - GstClockTime base_time; - GstClockTime current_time; - guint64 running_time_sample; - gint running_time_segment; - gint current_segment; - gint segment_skew; - gint sps; - - /* samples per segment */ - sps = ringbuffer->samples_per_seg; - - /* get the current time */ - current_time = gst_clock_get_time (clock); - - /* get the basetime */ - base_time = GST_ELEMENT_CAST (src)->base_time; - - /* get the running_time */ - running_time = current_time - base_time; - - /* the running_time converted to a sample (relative to the ringbuffer) */ - running_time_sample = - gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND); - - /* the segmentnr corrensponding to running_time, round down */ - running_time_segment = running_time_sample / sps; - - /* the segment currently read from the ringbuffer */ - current_segment = sample / sps; - - /* the skew we have between running_time and the ringbuffertime */ - segment_skew = running_time_segment - current_segment; - - GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT - "\n timestamp = %" GST_TIME_FORMAT - "\n running_time_segment = %d" - "\n current_segment = %d" - "\n segment_skew = %d", - GST_TIME_ARGS (running_time), - GST_TIME_ARGS (timestamp), - running_time_segment, current_segment, segment_skew); - - /* Resync the ringbuffer if: - * 1. We get one segment into the future. - * This is clearly a lie, because we can't - * possibly have a buffer with timestamp 1 at - * time 0. (unless it has time-travelled...) - * - * 2. We are more than the length of the ringbuffer behind. - * The length of the ringbuffer then gets to dictate - * the threshold for what is concidered "too late" - * - * 3. If this is our first buffer. - * We know that we should catch up to running_time - * the first time we are ran. - */ - if ((segment_skew < 0) || - (segment_skew >= ringbuffer->spec.segtotal) || - (current_segment == 0)) { - gint segments_written; - gint first_segment; - gint last_segment; - gint new_last_segment; - gint segment_diff; - gint new_first_segment; - guint64 new_sample; - - /* we are going to say that the last segment was captured at the current time - (running_time), minus one segment of creation-latency in the ringbuffer. - This can be thought of as: The segment arrived in the ringbuffer at time X, and - that means it was created at time X - (one segment). */ - new_last_segment = running_time_segment - 1; - - /* for better readablity */ - first_segment = current_segment; - - /* get the amount of segments written from the device by now */ - segments_written = g_atomic_int_get (&ringbuffer->segdone); - - /* subtract the base to segments_written to get the number of the - last written segment in the ringbuffer (one segment written = segment 0) */ - last_segment = segments_written - ringbuffer->segbase - 1; - - /* we see how many segments the ringbuffer was timeshifted */ - segment_diff = new_last_segment - last_segment; - - /* we move the first segment an equal amount */ - new_first_segment = first_segment + segment_diff; - - /* and we also move the segmentbase the same amount */ - ringbuffer->segbase -= segment_diff; - - /* we calculate the new sample value */ - new_sample = ((guint64) new_first_segment) * sps; - - /* and get the relative time to this -> our new timestamp */ - timestamp = - gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate); - - /* we update the next sample accordingly */ - src->next_sample = new_sample + samples; - - GST_DEBUG_OBJECT (bsrc, - "Timeshifted the ringbuffer with %d segments: " - "Updating the timestamp to %" GST_TIME_FORMAT ", " - "and src->next_sample to %" G_GUINT64_FORMAT, segment_diff, - GST_TIME_ARGS (timestamp), src->next_sample); - } - break; - } - case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP: - { - GstClockTime base_time, latency; - - /* We are slaved to another clock, take running time of the pipeline clock and - * timestamp against it. Somebody else in the pipeline should figure out the - * clock drift. We keep the duration we calculated above. */ - timestamp = gst_clock_get_time (clock); - base_time = GST_ELEMENT_CAST (src)->base_time; - - if (timestamp > base_time) - timestamp -= base_time; - else - timestamp = 0; - - /* subtract latency */ - latency = - gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate); - if (timestamp > latency) - timestamp -= latency; - else - timestamp = 0; - } - case GST_BASE_AUDIO_SRC_SLAVE_NONE: - break; - } - } else { - GstClockTime base_time; - - /* to get the timestamp against the clock we also need to add our offset */ - timestamp = gst_audio_clock_adjust (clock, timestamp); - - /* we are not slaved, subtract base_time */ - base_time = GST_ELEMENT_CAST (src)->base_time; - - if (timestamp > base_time) { - timestamp -= base_time; - GST_LOG_OBJECT (src, - "buffer timestamp %" GST_TIME_FORMAT " (base_time %" GST_TIME_FORMAT - ")", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (base_time)); - } else { - GST_LOG_OBJECT (src, - "buffer timestamp 0, ts %" GST_TIME_FORMAT " <= base_time %" - GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), - GST_TIME_ARGS (base_time)); - timestamp = 0; - } - } - -no_sync: - GST_OBJECT_UNLOCK (src); - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - GST_BUFFER_OFFSET (buf) = sample; - GST_BUFFER_OFFSET_END (buf) = sample + samples; - - *outbuf = buf; - - return GST_FLOW_OK; - - /* ERRORS */ -wrong_state: - { - GST_DEBUG_OBJECT (src, "ringbuffer in wrong state"); - return GST_FLOW_WRONG_STATE; - } -wrong_offset: - { - GST_ELEMENT_ERROR (src, RESOURCE, SEEK, - (NULL), ("resource can only be operated on sequentially but offset %" - G_GUINT64_FORMAT " was given", offset)); - return GST_FLOW_ERROR; - } -stopped: - { - gst_buffer_unref (buf); - GST_DEBUG_OBJECT (src, "ringbuffer stopped"); - return GST_FLOW_WRONG_STATE; - } -} - -/** - * gst_base_audio_src_create_ringbuffer: - * @src: a #GstBaseAudioSrc. - * - * Create and return the #GstRingBuffer for @src. This function will call the - * ::create_ringbuffer vmethod and will set @src as the parent of the returned - * buffer (see gst_object_set_parent()). - * - * Returns: The new ringbuffer of @src. - */ -GstRingBuffer * -gst_base_audio_src_create_ringbuffer (GstBaseAudioSrc * src) -{ - GstBaseAudioSrcClass *bclass; - GstRingBuffer *buffer = NULL; - - bclass = GST_BASE_AUDIO_SRC_GET_CLASS (src); - if (bclass->create_ringbuffer) - buffer = bclass->create_ringbuffer (src); - - if (G_LIKELY (buffer)) - gst_object_set_parent (GST_OBJECT_CAST (buffer), GST_OBJECT_CAST (src)); - - return buffer; -} - -static GstStateChangeReturn -gst_base_audio_src_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - GST_DEBUG_OBJECT (src, "NULL->READY"); - GST_OBJECT_LOCK (src); - if (src->ringbuffer == NULL) { - gst_audio_clock_reset (GST_AUDIO_CLOCK (src->clock), 0); - src->ringbuffer = gst_base_audio_src_create_ringbuffer (src); - } - GST_OBJECT_UNLOCK (src); - if (!gst_ring_buffer_open_device (src->ringbuffer)) - goto open_failed; - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (src, "READY->PAUSED"); - src->next_sample = -1; - gst_ring_buffer_set_flushing (src->ringbuffer, FALSE); - gst_ring_buffer_may_start (src->ringbuffer, FALSE); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - GST_DEBUG_OBJECT (src, "PAUSED->PLAYING"); - gst_ring_buffer_may_start (src->ringbuffer, TRUE); - break; - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - GST_DEBUG_OBJECT (src, "PLAYING->PAUSED"); - gst_ring_buffer_may_start (src->ringbuffer, FALSE); - gst_ring_buffer_pause (src->ringbuffer); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (src, "PAUSED->READY"); - gst_ring_buffer_set_flushing (src->ringbuffer, TRUE); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (src, "PAUSED->READY"); - gst_ring_buffer_release (src->ringbuffer); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - GST_DEBUG_OBJECT (src, "READY->NULL"); - gst_ring_buffer_close_device (src->ringbuffer); - GST_OBJECT_LOCK (src); - gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer)); - src->ringbuffer = NULL; - GST_OBJECT_UNLOCK (src); - break; - default: - break; - } - - return ret; - - /* ERRORS */ -open_failed: - { - /* subclass must post a meaningfull error message */ - GST_DEBUG_OBJECT (src, "open failed"); - return GST_STATE_CHANGE_FAILURE; - } - -} diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c.rej b/gst-libs/gst/audio/gstbaseaudiosrc.c.rej deleted file mode 100644 index 773c6e8..0000000 --- a/gst-libs/gst/audio/gstbaseaudiosrc.c.rej +++ /dev/null @@ -1,127 +0,0 @@ -*************** gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, -*** 865,935 **** - running_time_segment = running_time_sample / sps; - - /* the segment currently read from the ringbuffer */ -- current_segment = sample / sps; -- -- /* the skew we have between running_time and the ringbuffertime */ -- segment_skew = running_time_segment - current_segment; -- -- GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT -- "\n timestamp = %" GST_TIME_FORMAT -- "\n running_time_segment = %d" -- "\n current_segment = %d" -- "\n segment_skew = %d", - GST_TIME_ARGS (running_time), - GST_TIME_ARGS (timestamp), -- running_time_segment, current_segment, segment_skew); - - /* Resync the ringbuffer if: -- * 1. We are more than the length of the ringbuffer in front. -- * The length of the ringbuffer then gets to dictate -- * the threshold for what is concidered "too far ahead" -- * -- * 2. We are more than the length of the ringbuffer behind. - * The length of the ringbuffer then gets to dictate - * the threshold for what is concidered "too late" - * -- * 3. If this is our first buffer. - * We know that we should catch up to running_time - * the first time we are ran. - */ -- if ((segment_skew <= -ringbuffer->spec.segtotal) || -- (segment_skew >= ringbuffer->spec.segtotal) || -- (current_segment == 0)) { -- gint segments_written; -- gint first_segment; -- gint last_segment; -- gint new_last_segment; - gint segment_diff; -- gint new_first_segment; - guint64 new_sample; - -- /* we are going to say that the last segment was captured at the current time -- (running_time), minus one segment of creation-latency in the ringbuffer. -- This can be thought of as: The segment arrived in the ringbuffer at time X, and -- that means it was created at time X - (one segment). */ -- new_last_segment = running_time_segment - 1; -- -- /* for better readablity */ -- first_segment = current_segment; -- -- /* get the amount of segments written from the device by now */ -- segments_written = g_atomic_int_get (&ringbuffer->segdone); -- -- /* subtract the base to segments_written to get the number of the -- last written segment in the ringbuffer (one segment written = segment 0) */ -- last_segment = segments_written - ringbuffer->segbase - 1; -- -- /* we see how many segments the ringbuffer was timeshifted */ -- segment_diff = new_last_segment - last_segment; - -- /* we move the first segment an equal amount */ -- new_first_segment = first_segment + segment_diff; - -- /* and we also move the segmentbase the same amount */ -- ringbuffer->segbase -= segment_diff; - - /* we calculate the new sample value */ -- new_sample = ((guint64) new_first_segment) * sps; - - /* and get the relative time to this -> our new timestamp */ - timestamp = ---- 874,926 ---- - running_time_segment = running_time_sample / sps; - - /* the segment currently read from the ringbuffer */ -+ last_read_segment = sample / sps; -+ -+ /* the skew we have between running_time and the ringbuffertime (last written to) */ -+ segment_skew = running_time_segment - last_written_segment; -+ -+ GST_DEBUG_OBJECT (bsrc, -+ "\n running_time = %" GST_TIME_FORMAT -+ "\n timestamp = %" GST_TIME_FORMAT -+ "\n running_time_segment = %d" -+ "\n last_written_segment = %d" -+ "\n segment_skew (running time segment - last_written_segment) = %d" -+ "\n last_read_segment = %d", - GST_TIME_ARGS (running_time), - GST_TIME_ARGS (timestamp), -+ running_time_segment, -+ last_written_segment, -+ segment_skew, -+ last_read_segment); - - /* Resync the ringbuffer if: -+ -+ * 1. We are more than the length of the ringbuffer behind. - * The length of the ringbuffer then gets to dictate - * the threshold for what is concidered "too late" - * -+ * 2. If this is our first buffer. - * We know that we should catch up to running_time - * the first time we are ran. - */ -+ if ((segment_skew >= ringbuffer->spec.segtotal) || -+ (last_read_segment == 0)) -+ { -+ gint new_read_segment; - gint segment_diff; - guint64 new_sample; - -+ /* the difference between running_time and the last written segment */ -+ segment_diff = running_time_segment - last_written_segment; - -+ /* advance the ringbuffer */ -+ gst_ring_buffer_advance(ringbuffer, segment_diff); - -+ /* we move the new read segment to the last known written segment */ -+ new_read_segment = g_atomic_int_get (&ringbuffer->segdone) - ringbuffer->segbase; - - /* we calculate the new sample value */ -+ new_sample = ((guint64) new_read_segment) * sps; - - /* and get the relative time to this -> our new timestamp */ - timestamp = diff --git a/gst-libs/gst/audio/gstringbufferthread.c b/gst-libs/gst/audio/gstringbufferthread.c deleted file mode 100644 index 6d23e19..0000000 --- a/gst-libs/gst/audio/gstringbufferthread.c +++ /dev/null @@ -1,362 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * gstaudioringbuffer.c: simple audio ringbuffer base class - * - * 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 - -#include "gstringbufferthread.h" - -GST_DEBUG_CATEGORY_STATIC (gst_ring_buffer_thread_debug); -#define GST_CAT_DEFAULT gst_ring_buffer_thread_debug - -static void gst_ring_buffer_thread_class_init (GstRingBufferThreadClass * - klass); -static void gst_ring_buffer_thread_init (GstRingBufferThread * ringbuffer, - GstRingBufferThreadClass * klass); -static void gst_ring_buffer_thread_dispose (GObject * object); -static void gst_ring_buffer_thread_finalize (GObject * object); - -static GstRingBufferClass *ring_parent_class = NULL; - -GType -gst_ring_buffer_thread_get_type (void) -{ - static GType ringbuffer_type = 0; - - if (!ringbuffer_type) { - static const GTypeInfo ringbuffer_info = { - sizeof (GstRingBufferThreadClass), - NULL, - NULL, - (GClassInitFunc) gst_ring_buffer_thread_class_init, - NULL, - NULL, - sizeof (GstRingBufferThread), - 0, - (GInstanceInitFunc) gst_ring_buffer_thread_init, - NULL - }; - - ringbuffer_type = - g_type_register_static (GST_TYPE_OBJECT, "GstRingBufferThread", - &ringbuffer_info, 0); - - GST_DEBUG_CATEGORY_INIT (gst_ring_buffer_thread_debug, "ringbufferthread", - 0, "ringbuffer thread"); - } - return ringbuffer_type; -} - -static void -gst_ring_buffer_thread_class_init (GstRingBufferThreadClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - ring_parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_ring_buffer_thread_dispose; - gobject_class->finalize = gst_ring_buffer_thread_finalize; -} - -typedef gint (*ProcessFunc) (GstAudioRingBuffer * buf, gpointer data, - guint length); - -/* this internal thread does nothing else but write samples to the audio device. - * It will write each segment in the ringbuffer and will update the play - * pointer. - * The start/stop methods control the thread. - */ -static void -ring_buffer_thread_thread_func (GstRingBufferThread * thread) -{ - GstElement *parent = NULL; - GstMessage *message; - GValue val = { 0 }; - GstAudioRingBuffer *capture, *playback; - ProcessFunc writefunc = NULL, readfunc = NULL; - gint preroll = 1; - - GST_DEBUG_OBJECT (thread, "enter thread"); - - GST_OBJECT_LOCK (thread); - GST_DEBUG_OBJECT (thread, "signal wait"); - GST_RING_BUFFER_THREAD_SIGNAL (thread); - if ((capture = thread->capture)) - gst_object_ref (capture); - if ((playback = thread->playback)) - gst_object_ref (playback); - GST_OBJECT_UNLOCK (thread); - - if (capture) - readfunc = GST_AUDIO_RING_BUFFER_GET_CLASS (capture)->process; - if (playback) - writefunc = GST_AUDIO_RING_BUFFER_GET_CLASS (playback)->process; - - if (parent) { - g_value_init (&val, G_TYPE_POINTER); - g_value_set_pointer (&val, thread->thread); - message = gst_message_new_stream_status (GST_OBJECT_CAST (thread), - GST_STREAM_STATUS_TYPE_ENTER, NULL); - gst_message_set_stream_status_object (message, &val); - GST_DEBUG_OBJECT (thread, "posting ENTER stream status"); - gst_element_post_message (parent, message); - } - - while (TRUE) { - gint left, processed; - guint8 *read_ptr, *write_ptr; - gint read_seg, write_seg; - gint read_len, write_len; - gboolean read_active, write_active; - - if (playback) - write_active = - gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (playback), - &write_seg, &write_ptr, &write_len); - else - write_active = FALSE; - - if (playback) { - if (!write_active) { - write_ptr = GST_RING_BUFFER_CAST (playback)->empty_seg; - write_len = GST_RING_BUFFER_CAST (playback)->spec.segsize; - } - - left = write_len; - do { - processed = writefunc (playback, write_ptr, left); - GST_LOG_OBJECT (thread, "written %d bytes of %d from segment %d", - processed, left, write_seg); - if (processed < 0 || processed > left) { - /* might not be critical, it e.g. happens when aborting playback */ - GST_WARNING_OBJECT (thread, - "error writing data in %s (reason: %s), skipping segment (left: %d, processed: %d)", - GST_DEBUG_FUNCPTR_NAME (writefunc), - (errno > 1 ? g_strerror (errno) : "unknown"), left, processed); - break; - } - left -= processed; - write_ptr += processed; - } while (left > 0); - - /* we wrote one segment */ - gst_ring_buffer_advance (GST_RING_BUFFER_CAST (playback), 1); - - if (preroll > 0) { - /* do not start reading until we have read enough data */ - preroll--; - GST_DEBUG_OBJECT (thread, "need more preroll"); - continue; - } - } - - - if (capture) - read_active = - gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (capture), - &read_seg, &read_ptr, &read_len); - else - read_active = FALSE; - - if (capture) { - left = read_len; - do { - processed = readfunc (capture, read_ptr, left); - GST_LOG_OBJECT (thread, "read %d bytes of %d from segment %d", - processed, left, read_seg); - if (processed < 0 || processed > left) { - /* might not be critical, it e.g. happens when aborting playback */ - GST_WARNING_OBJECT (thread, - "error reading data in %s (reason: %s), skipping segment (left: %d, processed: %d)", - GST_DEBUG_FUNCPTR_NAME (readfunc), - (errno > 1 ? g_strerror (errno) : "unknown"), left, processed); - break; - } - left -= processed; - read_ptr += processed; - } while (left > 0); - - if (read_active) - /* we read one segment */ - gst_ring_buffer_advance (GST_RING_BUFFER_CAST (capture), 1); - } - - if (!read_active && !write_active) { - GST_OBJECT_LOCK (thread); - if (!thread->running) - goto stop_running; - GST_DEBUG_OBJECT (thread, "signal wait"); - GST_RING_BUFFER_THREAD_SIGNAL (thread); - GST_DEBUG_OBJECT (thread, "wait for action"); - GST_RING_BUFFER_THREAD_WAIT (thread); - GST_DEBUG_OBJECT (thread, "got signal"); - if (!thread->running) - goto stop_running; - GST_DEBUG_OBJECT (thread, "continue running"); - GST_OBJECT_UNLOCK (thread); - } - } - - /* Will never be reached */ - g_assert_not_reached (); - return; - - /* ERROR */ -stop_running: - { - GST_OBJECT_UNLOCK (thread); - GST_DEBUG_OBJECT (thread, "stop running, exit thread"); - if (parent) { - message = gst_message_new_stream_status (GST_OBJECT_CAST (thread), - GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (thread)); - gst_message_set_stream_status_object (message, &val); - GST_DEBUG_OBJECT (thread, "posting LEAVE stream status"); - gst_element_post_message (parent, message); - } - return; - } -} - -static void -gst_ring_buffer_thread_init (GstRingBufferThread * thread, - GstRingBufferThreadClass * g_class) -{ - thread->running = FALSE; - thread->cond = g_cond_new (); -} - -static void -gst_ring_buffer_thread_dispose (GObject * object) -{ - GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object); - - GST_OBJECT_LOCK (thread); - if (thread->playback) { - gst_object_unref (thread->playback); - thread->playback = NULL; - } - if (thread->capture) { - gst_object_unref (thread->capture); - thread->capture = NULL; - } - GST_OBJECT_UNLOCK (thread); - - G_OBJECT_CLASS (ring_parent_class)->dispose (object); -} - -static void -gst_ring_buffer_thread_finalize (GObject * object) -{ - GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object); - - g_cond_free (thread->cond); - - G_OBJECT_CLASS (ring_parent_class)->finalize (object); -} - -gboolean -gst_ring_buffer_thread_activate (GstRingBufferThread * thread, gboolean active) -{ - GError *error = NULL; - - GST_OBJECT_LOCK (thread); - if (active) { - if (thread->active_count == 0) { - thread->running = TRUE; - GST_DEBUG_OBJECT (thread, "starting thread"); - thread->thread = - g_thread_create ((GThreadFunc) ring_buffer_thread_thread_func, thread, - TRUE, &error); - if (!thread->thread || error != NULL) - goto thread_failed; - - GST_DEBUG_OBJECT (thread, "waiting for thread"); - /* the object lock is taken */ - GST_RING_BUFFER_THREAD_WAIT (thread); - GST_DEBUG_OBJECT (thread, "thread is started"); - } - thread->active_count++; - } else { - if (thread->active_count == 1) { - thread->running = FALSE; - GST_DEBUG_OBJECT (thread, "signal wait"); - GST_RING_BUFFER_THREAD_SIGNAL (thread); - GST_OBJECT_UNLOCK (thread); - - /* join the thread */ - g_thread_join (thread->thread); - - GST_OBJECT_LOCK (thread); - } - thread->active_count--; - } - GST_OBJECT_UNLOCK (thread); - - return TRUE; - - /* ERRORS */ -thread_failed: - { - if (error) - GST_ERROR_OBJECT (thread, "could not create thread %s", error->message); - else - GST_ERROR_OBJECT (thread, "could not create thread for unknown reason"); - thread->running = FALSE; - GST_OBJECT_UNLOCK (thread); - return FALSE; - } -} - -gboolean -gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread * thread, - GstAudioRingBuffer * buf) -{ - GstAudioRingBuffer *old, **new; - - g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE); - - if (buf->mode == GST_AUDIO_RING_BUFFER_MODE_PLAYBACK) - new = &thread->playback; - else - new = &thread->capture; - - old = *new; - if (buf) - gst_object_ref (buf); - *new = buf; - if (old) - gst_object_unref (old); - - return TRUE; -} - -gboolean -gst_ring_buffer_thread_start (GstRingBufferThread * thread) -{ - g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE); - - GST_RING_BUFFER_THREAD_SIGNAL (thread); - - return TRUE; -} diff --git a/gst-libs/gst/audio/gstringbufferthread.h b/gst-libs/gst/audio/gstringbufferthread.h deleted file mode 100644 index 70498c5b..0000000 --- a/gst-libs/gst/audio/gstringbufferthread.h +++ /dev/null @@ -1,93 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * gstaudioringbuffer.h: - * - * 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 __GST_RING_BUFFER_THREAD_H__ -#define __GST_RING_BUFFER_THREAD_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_RING_BUFFER_THREAD (gst_ring_buffer_thread_get_type()) -#define GST_RING_BUFFER_THREAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThread)) -#define GST_RING_BUFFER_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass)) -#define GST_RING_BUFFER_THREAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass)) -#define GST_IS_RING_BUFFER_THREAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RING_BUFFER_THREAD)) -#define GST_IS_RING_BUFFER_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RING_BUFFER_THREAD)) -#define GST_RING_BUFFER_THREAD_CAST(obj) ((GstRingBufferThread *)obj) - -typedef struct _GstRingBufferThread GstRingBufferThread; -typedef struct _GstRingBufferThreadClass GstRingBufferThreadClass; - -#include - -#define GST_RING_BUFFER_THREAD_GET_COND(buf) (((GstRingBufferThread *)buf)->cond) -#define GST_RING_BUFFER_THREAD_WAIT(buf) (g_cond_wait (GST_RING_BUFFER_THREAD_GET_COND (buf), GST_OBJECT_GET_LOCK (buf))) -#define GST_RING_BUFFER_THREAD_SIGNAL(buf) (g_cond_signal (GST_RING_BUFFER_THREAD_GET_COND (buf))) -#define GST_RING_BUFFER_THREAD_BROADCAST(buf)(g_cond_broadcast (GST_RING_BUFFER_THREAD_GET_COND (buf))) - -/** - * GstRingBufferThread: - * - * Opaque #GstRingBufferThread. - */ -struct _GstRingBufferThread { - GstObject parent; - - gint active_count; - - /*< private >*/ /* with LOCK */ - GThread *thread; - gboolean running; - GCond *cond; - - GstAudioRingBuffer *playback; - GstAudioRingBuffer *capture; - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; -}; - -/** - * GstRingBufferThreadClass: - * @parent_class: the parent class structure. - * - * #GstRingBufferThread class. Override the vmethods to implement functionality. - */ -struct _GstRingBufferThreadClass { - GstObjectClass parent_class; - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; -}; - -GType gst_ring_buffer_thread_get_type(void); - -gboolean gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread *thread, GstAudioRingBuffer *buf); - -gboolean gst_ring_buffer_thread_activate (GstRingBufferThread *thread, gboolean active); - -gboolean gst_ring_buffer_thread_start (GstRingBufferThread *thread); - -G_END_DECLS - -#endif /* __GST_RING_BUFFER_THREAD_H__ */ diff --git a/gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch b/gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch deleted file mode 100644 index 0a2041a..0000000 --- a/gst-libs/gst/cdda/gst-plugins-base-sha1-2.patch +++ /dev/null @@ -1,617 +0,0 @@ -? foo -Index: Makefile.am -=================================================================== -RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/Makefile.am,v -retrieving revision 1.4 -diff -u -p -u -p -r1.4 Makefile.am ---- Makefile.am 3 Apr 2008 06:39:27 -0000 1.4 -+++ Makefile.am 21 Aug 2008 14:17:21 -0000 -@@ -1,9 +1,7 @@ - lib_LTLIBRARIES = libgstcdda-@GST_MAJORMINOR@.la - - libgstcdda_@GST_MAJORMINOR@_la_SOURCES = \ -- gstcddabasesrc.c \ -- sha1.c \ -- sha1.h -+ gstcddabasesrc.c - - libgstcdda_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/cdda - libgstcdda_@GST_MAJORMINOR@include_HEADERS = \ -Index: gstcddabasesrc.c -=================================================================== -RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/gstcddabasesrc.c,v -retrieving revision 1.19 -diff -u -p -u -p -r1.19 gstcddabasesrc.c ---- gstcddabasesrc.c 28 May 2008 15:48:33 -0000 1.19 -+++ gstcddabasesrc.c 21 Aug 2008 14:17:21 -0000 -@@ -1084,36 +1084,35 @@ cddb_sum (gint n) - return ret; - } - --#include "sha1.h" -- - static void - gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src) - { - GString *s; -- SHA_INFO sha; -+ GChecksum *sha; - guchar digest[20]; - gchar *ptr; - gchar tmp[9]; - gulong i; - guint leadout_sector; -+ gsize digest_len; - - s = g_string_new (NULL); - - leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET; - - /* generate SHA digest */ -- sha_init (&sha); -+ sha = g_checksum_new (G_CHECKSUM_SHA1); - g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num); - g_string_append_printf (s, "%02X", src->tracks[0].num); -- sha_update (&sha, (SHA_BYTE *) tmp, 2); -+ g_checksum_update (sha, (guchar *) tmp, 2); - - g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num); - g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num); -- sha_update (&sha, (SHA_BYTE *) tmp, 2); -+ g_checksum_update (sha, (guchar *) tmp, 2); - - g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector); - g_string_append_printf (s, " %08X", leadout_sector); -- sha_update (&sha, (SHA_BYTE *) tmp, 8); -+ g_checksum_update (sha, (guchar *) tmp, 8); - - for (i = 0; i < 99; i++) { - if (i < src->num_tracks) { -@@ -1121,15 +1120,17 @@ gst_cddabasesrc_calculate_musicbrainz_di - - g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset); - g_string_append_printf (s, " %08X", frame_offset); -- sha_update (&sha, (SHA_BYTE *) tmp, 8); -+ g_checksum_update (sha, (guchar *) tmp, 8); - } else { -- sha_update (&sha, (SHA_BYTE *) "00000000", 8); -+ g_checksum_update (sha, (guchar *) "00000000", 8); - } - } -- sha_final (digest, &sha); -+ digest_len = 20; -+ g_checksum_get_digest (sha, (guint8 *) &digest, &digest_len); - - /* re-encode to base64 */ -- ptr = g_base64_encode (digest, 20); -+ ptr = g_base64_encode (digest, digest_len); -+ g_checksum_free (sha); - i = strlen (ptr); - - g_assert (i < sizeof (src->mb_discid) + 1); -Index: sha1.c -=================================================================== -RCS file: sha1.c -diff -N sha1.c ---- sha1.c 27 Feb 2008 10:42:08 -0000 1.2 -+++ /dev/null 1 Jan 1970 00:00:00 -0000 -@@ -1,450 +0,0 @@ --/* (PD) 2001 The Bitzi Corporation -- * Please see file COPYING or http://bitzi.com/publicdomain -- * for more info. -- * -- * NIST Secure Hash Algorithm -- * heavily modified by Uwe Hollerbach -- * from Peter C. Gutmann's implementation as found in -- * Applied Cryptography by Bruce Schneier -- * Further modifications to include the "UNRAVEL" stuff, below -- * -- * This code is in the public domain -- * -- * $Id: sha1.c,v 1.2 2008-02-27 10:42:08 slomo Exp $ -- */ -- --#ifdef HAVE_CONFIG_H --#include "config.h" --#endif --#include --#define SHA_BYTE_ORDER G_BYTE_ORDER -- --#include --#include "sha1.h" -- --/* UNRAVEL should be fastest & biggest */ --/* UNROLL_LOOPS should be just as big, but slightly slower */ --/* both undefined should be smallest and slowest */ -- --#define UNRAVEL --/* #define UNROLL_LOOPS */ -- --/* SHA f()-functions */ -- --#define f1(x,y,z) ((x & y) | (~x & z)) --#define f2(x,y,z) (x ^ y ^ z) --#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) --#define f4(x,y,z) (x ^ y ^ z) -- --/* SHA constants */ -- --#define CONST1 0x5a827999L --#define CONST2 0x6ed9eba1L --#define CONST3 0x8f1bbcdcL --#define CONST4 0xca62c1d6L -- --/* truncate to 32 bits -- should be a null op on 32-bit machines */ -- --#define T32(x) ((x) & 0xffffffffL) -- --/* 32-bit rotate */ -- --#define R32(x,n) T32(((x << n) | (x >> (32 - n)))) -- --/* the generic case, for when the overall rotation is not unraveled */ -- --#define FG(n) \ -- T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ -- E = D; D = C; C = R32(B,30); B = A; A = T -- --/* specific cases, for when the overall rotation is unraveled */ -- --#define FA(n) \ -- T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30) -- --#define FB(n) \ -- E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30) -- --#define FC(n) \ -- D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30) -- --#define FD(n) \ -- C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30) -- --#define FE(n) \ -- B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30) -- --#define FT(n) \ -- A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30) -- --/* do SHA transformation */ -- --static void --sha_transform (SHA_INFO * sha_info) --{ -- int i; -- SHA_BYTE *dp; -- SHA_LONG T, A, B, C, D, E, W[80], *WP; -- -- dp = sha_info->data; -- --/* --the following makes sure that at least one code block below is --traversed or an error is reported, without the necessity for nested --preprocessor if/else/endif blocks, which are a great pain in the --nether regions of the anatomy... --*/ --#undef SWAP_DONE -- --#if (SHA_BYTE_ORDER == 1234) --#define SWAP_DONE -- for (i = 0; i < 16; ++i) { -- memcpy (&T, dp, sizeof (SHA_LONG)); -- dp += 4; -- W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | -- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); -- } --#endif /* SHA_BYTE_ORDER == 1234 */ -- --#if (SHA_BYTE_ORDER == 4321) --#define SWAP_DONE -- for (i = 0; i < 16; ++i) { -- memcpy (&T, dp, sizeof (SHA_LONG)); -- dp += 4; -- W[i] = T32 (T); -- } --#endif /* SHA_BYTE_ORDER == 4321 */ -- --#if (SHA_BYTE_ORDER == 12345678) --#define SWAP_DONE -- for (i = 0; i < 16; i += 2) { -- memcpy (&T, dp, sizeof (SHA_LONG)); -- dp += 8; -- W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | -- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); -- T >>= 32; -- W[i + 1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | -- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); -- } --#endif /* SHA_BYTE_ORDER == 12345678 */ -- --#if (SHA_BYTE_ORDER == 87654321) --#define SWAP_DONE -- for (i = 0; i < 16; i += 2) { -- memcpy (&T, dp, sizeof (SHA_LONG)); -- dp += 8; -- W[i] = T32 (T >> 32); -- W[i + 1] = T32 (T); -- } --#endif /* SHA_BYTE_ORDER == 87654321 */ -- --#ifndef SWAP_DONE --#error Unknown byte order -- you need to add code here --#endif /* SWAP_DONE */ -- -- for (i = 16; i < 80; ++i) { -- W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; --#if (SHA_VERSION == 1) -- W[i] = R32 (W[i], 1); --#endif /* SHA_VERSION */ -- } -- A = sha_info->digest[0]; -- B = sha_info->digest[1]; -- C = sha_info->digest[2]; -- D = sha_info->digest[3]; -- E = sha_info->digest[4]; -- WP = W; --#ifdef UNRAVEL -- FA (1); -- FB (1); -- FC (1); -- FD (1); -- FE (1); -- FT (1); -- FA (1); -- FB (1); -- FC (1); -- FD (1); -- FE (1); -- FT (1); -- FA (1); -- FB (1); -- FC (1); -- FD (1); -- FE (1); -- FT (1); -- FA (1); -- FB (1); -- FC (2); -- FD (2); -- FE (2); -- FT (2); -- FA (2); -- FB (2); -- FC (2); -- FD (2); -- FE (2); -- FT (2); -- FA (2); -- FB (2); -- FC (2); -- FD (2); -- FE (2); -- FT (2); -- FA (2); -- FB (2); -- FC (2); -- FD (2); -- FE (3); -- FT (3); -- FA (3); -- FB (3); -- FC (3); -- FD (3); -- FE (3); -- FT (3); -- FA (3); -- FB (3); -- FC (3); -- FD (3); -- FE (3); -- FT (3); -- FA (3); -- FB (3); -- FC (3); -- FD (3); -- FE (3); -- FT (3); -- FA (4); -- FB (4); -- FC (4); -- FD (4); -- FE (4); -- FT (4); -- FA (4); -- FB (4); -- FC (4); -- FD (4); -- FE (4); -- FT (4); -- FA (4); -- FB (4); -- FC (4); -- FD (4); -- FE (4); -- FT (4); -- FA (4); -- FB (4); -- sha_info->digest[0] = T32 (sha_info->digest[0] + E); -- sha_info->digest[1] = T32 (sha_info->digest[1] + T); -- sha_info->digest[2] = T32 (sha_info->digest[2] + A); -- sha_info->digest[3] = T32 (sha_info->digest[3] + B); -- sha_info->digest[4] = T32 (sha_info->digest[4] + C); --#else /* !UNRAVEL */ --#ifdef UNROLL_LOOPS -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (1); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (2); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (3); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); -- FG (4); --#else /* !UNROLL_LOOPS */ -- for (i = 0; i < 20; ++i) { -- FG (1); -- } -- for (i = 20; i < 40; ++i) { -- FG (2); -- } -- for (i = 40; i < 60; ++i) { -- FG (3); -- } -- for (i = 60; i < 80; ++i) { -- FG (4); -- } --#endif /* !UNROLL_LOOPS */ -- sha_info->digest[0] = T32 (sha_info->digest[0] + A); -- sha_info->digest[1] = T32 (sha_info->digest[1] + B); -- sha_info->digest[2] = T32 (sha_info->digest[2] + C); -- sha_info->digest[3] = T32 (sha_info->digest[3] + D); -- sha_info->digest[4] = T32 (sha_info->digest[4] + E); --#endif /* !UNRAVEL */ --} -- --/* initialize the SHA digest */ -- --void --sha_init (SHA_INFO * sha_info) --{ -- sha_info->digest[0] = 0x67452301L; -- sha_info->digest[1] = 0xefcdab89L; -- sha_info->digest[2] = 0x98badcfeL; -- sha_info->digest[3] = 0x10325476L; -- sha_info->digest[4] = 0xc3d2e1f0L; -- sha_info->count_lo = 0L; -- sha_info->count_hi = 0L; -- sha_info->local = 0; --} -- --/* update the SHA digest */ -- --void --sha_update (SHA_INFO * sha_info, SHA_BYTE * buffer, int count) --{ -- int i; -- SHA_LONG clo; -- -- clo = T32 (sha_info->count_lo + ((SHA_LONG) count << 3)); -- if (clo < sha_info->count_lo) { -- ++sha_info->count_hi; -- } -- sha_info->count_lo = clo; -- sha_info->count_hi += (SHA_LONG) count >> 29; -- if (sha_info->local) { -- i = SHA_BLOCKSIZE - sha_info->local; -- if (i > count) { -- i = count; -- } -- memcpy (((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); -- count -= i; -- buffer += i; -- sha_info->local += i; -- if (sha_info->local == SHA_BLOCKSIZE) { -- sha_transform (sha_info); -- } else { -- return; -- } -- } -- while (count >= SHA_BLOCKSIZE) { -- memcpy (sha_info->data, buffer, SHA_BLOCKSIZE); -- buffer += SHA_BLOCKSIZE; -- count -= SHA_BLOCKSIZE; -- sha_transform (sha_info); -- } -- memcpy (sha_info->data, buffer, count); -- sha_info->local = count; --} -- --/* finish computing the SHA digest */ -- --void --sha_final (unsigned char digest[20], SHA_INFO * sha_info) --{ -- int count; -- SHA_LONG lo_bit_count, hi_bit_count; -- -- lo_bit_count = sha_info->count_lo; -- hi_bit_count = sha_info->count_hi; -- count = (int) ((lo_bit_count >> 3) & 0x3f); -- ((SHA_BYTE *) sha_info->data)[count++] = 0x80; -- if (count > SHA_BLOCKSIZE - 8) { -- memset (((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); -- sha_transform (sha_info); -- memset ((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); -- } else { -- memset (((SHA_BYTE *) sha_info->data) + count, 0, -- SHA_BLOCKSIZE - 8 - count); -- } -- sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff); -- sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff); -- sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff); -- sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff); -- sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff); -- sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff); -- sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff); -- sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff); -- sha_transform (sha_info); -- digest[0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); -- digest[1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); -- digest[2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); -- digest[3] = (unsigned char) ((sha_info->digest[0]) & 0xff); -- digest[4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); -- digest[5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); -- digest[6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); -- digest[7] = (unsigned char) ((sha_info->digest[1]) & 0xff); -- digest[8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); -- digest[9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); -- digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); -- digest[11] = (unsigned char) ((sha_info->digest[2]) & 0xff); -- digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); -- digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); -- digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); -- digest[15] = (unsigned char) ((sha_info->digest[3]) & 0xff); -- digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); -- digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); -- digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); -- digest[19] = (unsigned char) ((sha_info->digest[4]) & 0xff); --} -Index: sha1.h -=================================================================== -RCS file: sha1.h -diff -N sha1.h ---- sha1.h 13 Dec 2007 10:10:35 -0000 1.2 -+++ /dev/null 1 Jan 1970 00:00:00 -0000 -@@ -1,62 +0,0 @@ --/* NIST Secure Hash Algorithm */ --/* heavily modified by Uwe Hollerbach */ --/* from Peter C. Gutmann's implementation as found in */ --/* Applied Cryptography by Bruce Schneier */ --/* This code is in the public domain */ --/* $Id: sha1.h,v 1.2 2007-12-13 10:10:35 tpm Exp $ */ -- --#ifndef __GST_CDDA_SHA_H__ --#define __GST_CDDA_SHA_H__ -- --#include --#include -- --/* Useful defines & typedefs */ --typedef unsigned char SHA_BYTE; /* 8-bit quantity */ --typedef unsigned long SHA_LONG; /* 32-or-more-bit quantity */ -- --#define SHA_BLOCKSIZE 64 --#define SHA_DIGESTSIZE 20 -- --typedef struct { -- SHA_LONG digest[5]; /* message digest */ -- SHA_LONG count_lo, count_hi; /* 64-bit bit count */ -- SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ -- int local; /* unprocessed amount in data */ --} SHA_INFO; -- --#define sha_init __gst_cdda_sha_init --#define sha_update __gst_cdda_sha_update --#define sha_final __gst_cdda_sha_final -- --void sha_init(SHA_INFO *); --void sha_update(SHA_INFO *, SHA_BYTE *, int); --void sha_final(unsigned char [20], SHA_INFO *); -- --#define SHA_VERSION 1 -- --#ifdef HAVE_CONFIG_H --#include "config.h" -- -- --#ifdef WORDS_BIGENDIAN --# if SIZEOF_LONG == 4 --# define SHA_BYTE_ORDER 4321 --# elif SIZEOF_LONG == 8 --# define SHA_BYTE_ORDER 87654321 --# endif --#else --# if SIZEOF_LONG == 4 --# define SHA_BYTE_ORDER 1234 --# elif SIZEOF_LONG == 8 --# define SHA_BYTE_ORDER 12345678 --# endif --#endif -- --#else -- --#define SHA_BYTE_ORDER 1234 -- --#endif -- --#endif /* __GST_CDDA_SHA_H__ */ diff --git a/gst-libs/gst/cdda/gstcddabasesrc.c.orig b/gst-libs/gst/cdda/gstcddabasesrc.c.orig deleted file mode 100644 index 3a0bea8..0000000 --- a/gst-libs/gst/cdda/gstcddabasesrc.c.orig +++ /dev/null @@ -1,1594 +0,0 @@ -/* GStreamer - * Copyright (C) 1999 Erik Walthinsen - * Copyright (C) 2005 Tim-Philipp Müller - * - * 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. - */ - -/* TODO: - * - * - in ::start(), we want to post a tags message with an array or a list - * of tagslists of all tracks, so that applications know at least the - * number of tracks and all track durations immediately without having - * to do any querying. We have to decide what type and name to use for - * this array of track taglists. - * - * - FIX cddb discid calculation algorithm for mixed mode CDs - do we use - * offsets and duration of ALL tracks (data + audio) for the CDDB ID - * calculation, or only audio tracks? - * - * - Do we really need properties for the TOC bias/offset stuff? Wouldn't - * environment variables make much more sense? Do we need this at all - * (does it only affect ancient hardware?) - */ - -/** - * SECTION:gstcddabasesrc - * @short_description: Base class for CD digital audio (CDDA) sources - * - * - * - * Provides a base class for CDDA sources, which handles things like seeking, - * querying, discid calculation, tags, and buffer timestamping. - * - * Using GstCddaBaseSrc-based elements in applications - * - * GstCddaBaseSrc registers two #GstFormats of its own, namely - * the "track" format and the "sector" format. Applications will usually - * only find the "track" format interesting. You can retrieve that #GstFormat - * for use in seek events or queries with gst_format_get_by_nick("track"). - * - * - * In order to query the number of tracks, for example, an application would - * set the CDDA source element to READY or PAUSED state and then query the - * the number of tracks via gst_element_query_duration() using the track - * format acquired above. Applications can query the currently playing track - * in the same way. - * - * - * Alternatively, applications may retrieve the currently playing track and - * the total number of tracks from the taglist that will posted on the bus - * whenever the CD is opened or the currently playing track changes. The - * taglist will contain GST_TAG_TRACK_NUMBER and GST_TAG_TRACK_COUNT tags. - * - * - * Applications playing back CD audio using playbin and cdda://n URIs should - * issue a seek command in track format to change between tracks, rather than - * setting a new cdda://n+1 URI on playbin (as setting a new URI on playbin - * involves closing and re-opening the CD device, which is much much slower). - * - * Tags and meta-information - * - * CDDA sources will automatically emit a number of tags, details about which - * can be found in the libgsttag documentation. Those tags are: - * #GST_TAG_CDDA_CDDB_DISCID, #GST_TAG_CDDA_CDDB_DISCID_FULL, - * #GST_TAG_CDDA_MUSICBRAINZ_DISCID, #GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL, - * among others. - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include /* for strtol */ - -#include "gstcddabasesrc.h" -#include "gst/gst-i18n-plugin.h" - -GST_DEBUG_CATEGORY_STATIC (gst_cdda_base_src_debug); -#define GST_CAT_DEFAULT gst_cdda_base_src_debug - -#define DEFAULT_DEVICE "/dev/cdrom" - -#define CD_FRAMESIZE_RAW (2352) - -#define SECTORS_PER_SECOND (75) -#define SECTORS_PER_MINUTE (75*60) -#define SAMPLES_PER_SECTOR (CD_FRAMESIZE_RAW >> 2) -#define TIME_INTERVAL_FROM_SECTORS(sectors) ((SAMPLES_PER_SECTOR * sectors * GST_SECOND) / 44100) -#define SECTORS_FROM_TIME_INTERVAL(dtime) (dtime * 44100 / (SAMPLES_PER_SECTOR * GST_SECOND)) - -enum -{ - ARG_0, - ARG_MODE, - ARG_DEVICE, - ARG_TRACK, - ARG_TOC_OFFSET, - ARG_TOC_BIAS -}; - -static void gst_cdda_base_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_cdda_base_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_cdda_base_src_finalize (GObject * obj); -static const GstQueryType *gst_cdda_base_src_get_query_types (GstPad * pad); -static gboolean gst_cdda_base_src_query (GstBaseSrc * src, GstQuery * query); -static gboolean gst_cdda_base_src_handle_event (GstBaseSrc * basesrc, - GstEvent * event); -static gboolean gst_cdda_base_src_do_seek (GstBaseSrc * basesrc, - GstSegment * segment); -static void gst_cdda_base_src_setup_interfaces (GType type); -static gboolean gst_cdda_base_src_start (GstBaseSrc * basesrc); -static gboolean gst_cdda_base_src_stop (GstBaseSrc * basesrc); -static GstFlowReturn gst_cdda_base_src_create (GstPushSrc * pushsrc, - GstBuffer ** buf); -static gboolean gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc); -static void gst_cdda_base_src_update_duration (GstCddaBaseSrc * src); -static void gst_cdda_base_src_set_index (GstElement * src, GstIndex * index); -static GstIndex *gst_cdda_base_src_get_index (GstElement * src); - -GST_BOILERPLATE_FULL (GstCddaBaseSrc, gst_cdda_base_src, GstPushSrc, - GST_TYPE_PUSH_SRC, gst_cdda_base_src_setup_interfaces); - -#define SRC_CAPS \ - "audio/x-raw-int, " \ - "endianness = (int) BYTE_ORDER, " \ - "signed = (boolean) true, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ - "rate = (int) 44100, " \ - "channels = (int) 2" \ - -static GstStaticPadTemplate gst_cdda_base_src_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (SRC_CAPS) - ); - -/* our two formats */ -static GstFormat track_format; -static GstFormat sector_format; - -GType -gst_cdda_base_src_mode_get_type (void) -{ - static GType mode_type; /* 0 */ - static const GEnumValue modes[] = { - {GST_CDDA_BASE_SRC_MODE_NORMAL, "Stream consists of a single track", - "normal"}, - {GST_CDDA_BASE_SRC_MODE_CONTINUOUS, "Stream consists of the whole disc", - "continuous"}, - {0, NULL, NULL} - }; - - if (mode_type == 0) - mode_type = g_enum_register_static ("GstCddaBaseSrcMode", modes); - - return mode_type; -} - -static void -gst_cdda_base_src_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_cdda_base_src_src_template)); - - /* our very own formats */ - track_format = gst_format_register ("track", "CD track"); - sector_format = gst_format_register ("sector", "CD sector"); - - /* register CDDA tags */ - gst_tag_register_musicbrainz_tags (); - -#if 0 - ///// FIXME: what type to use here? /////// - gst_tag_register (GST_TAG_CDDA_TRACK_TAGS, GST_TAG_FLAG_META, GST_TYPE_TAG_LIST, "track-tags", "CDDA taglist for one track", gst_tag_merge_use_first); ///////////// FIXME: right function??? /////// -#endif - - GST_DEBUG_CATEGORY_INIT (gst_cdda_base_src_debug, "cddabasesrc", 0, - "CDDA Base Source"); -} - -static void -gst_cdda_base_src_class_init (GstCddaBaseSrcClass * klass) -{ - GstElementClass *element_class; - GstPushSrcClass *pushsrc_class; - GstBaseSrcClass *basesrc_class; - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - element_class = (GstElementClass *) klass; - basesrc_class = (GstBaseSrcClass *) klass; - pushsrc_class = (GstPushSrcClass *) klass; - - gobject_class->set_property = gst_cdda_base_src_set_property; - gobject_class->get_property = gst_cdda_base_src_get_property; - gobject_class->finalize = gst_cdda_base_src_finalize; - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE, - g_param_spec_string ("device", "Device", "CD device location", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE, - g_param_spec_enum ("mode", "Mode", "Mode", GST_TYPE_CDDA_BASE_SRC_MODE, - GST_CDDA_BASE_SRC_MODE_NORMAL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK, - g_param_spec_uint ("track", "Track", "Track", 1, 99, 1, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - -#if 0 - /* Do we really need this toc adjustment stuff as properties? does the user - * have a chance to set it in practice, e.g. when using sound-juicer, rb, - * totem, whatever? Shouldn't we rather use environment variables - * for this? (tpm) */ - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_OFFSET, - g_param_spec_int ("toc-offset", "Table of contents offset", - "Add sectors to the values reported", G_MININT, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_BIAS, - g_param_spec_boolean ("toc-bias", "Table of contents bias", - "Assume that the beginning offset of track 1 as reported in the TOC " - "will be addressed as LBA 0. Necessary for some Toshiba drives to " - "get track boundaries", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif - - element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index); - element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index); - - basesrc_class->start = GST_DEBUG_FUNCPTR (gst_cdda_base_src_start); - basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_cdda_base_src_stop); - basesrc_class->query = GST_DEBUG_FUNCPTR (gst_cdda_base_src_query); - basesrc_class->event = GST_DEBUG_FUNCPTR (gst_cdda_base_src_handle_event); - basesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_cdda_base_src_do_seek); - basesrc_class->is_seekable = - GST_DEBUG_FUNCPTR (gst_cdda_base_src_is_seekable); - - pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_cdda_base_src_create); -} - -static void -gst_cdda_base_src_init (GstCddaBaseSrc * src, GstCddaBaseSrcClass * klass) -{ - gst_pad_set_query_type_function (GST_BASE_SRC_PAD (src), - GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_query_types)); - - /* we're not live and we operate in time */ - gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); - gst_base_src_set_live (GST_BASE_SRC (src), FALSE); - - src->device = NULL; - src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL; - src->uri_track = -1; -} - -static void -gst_cdda_base_src_finalize (GObject * obj) -{ - GstCddaBaseSrc *cddasrc = GST_CDDA_BASE_SRC (obj); - - g_free (cddasrc->uri); - g_free (cddasrc->device); - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_cdda_base_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object); - - GST_OBJECT_LOCK (src); - - switch (prop_id) { - case ARG_MODE:{ - src->mode = g_value_get_enum (value); - break; - } - case ARG_DEVICE:{ - const gchar *dev = g_value_get_string (value); - - g_free (src->device); - if (dev && *dev) { - src->device = g_strdup (dev); - } else { - src->device = NULL; - } - break; - } - case ARG_TRACK:{ - guint track = g_value_get_uint (value); - - if (src->num_tracks > 0 && track > src->num_tracks) { - g_warning ("Invalid track %u", track); - } else if (track > 0 && src->tracks != NULL) { - src->cur_sector = src->tracks[track - 1].start; - src->uri_track = track; - } else { - src->uri_track = track; /* seek will be done in start() */ - } - break; - } - case ARG_TOC_OFFSET:{ - src->toc_offset = g_value_get_int (value); - break; - } - case ARG_TOC_BIAS:{ - src->toc_bias = g_value_get_boolean (value); - break; - } - default:{ - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - } - - GST_OBJECT_UNLOCK (src); -} - -static void -gst_cdda_base_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (object); - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object); - - GST_OBJECT_LOCK (src); - - switch (prop_id) { - case ARG_MODE: - g_value_set_enum (value, src->mode); - break; - case ARG_DEVICE:{ - if (src->device == NULL && klass->get_default_device != NULL) { - gchar *d = klass->get_default_device (src); - - if (d != NULL) { - g_value_set_string (value, DEFAULT_DEVICE); - g_free (d); - break; - } - } - if (src->device == NULL) - g_value_set_string (value, DEFAULT_DEVICE); - else - g_value_set_string (value, src->device); - break; - } - case ARG_TRACK:{ - if (src->num_tracks <= 0 && src->uri_track > 0) { - g_value_set_uint (value, src->uri_track); - } else { - g_value_set_uint (value, src->cur_track + 1); - } - break; - } - case ARG_TOC_OFFSET: - g_value_set_int (value, src->toc_offset); - break; - case ARG_TOC_BIAS: - g_value_set_boolean (value, src->toc_bias); - break; - default:{ - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - } - - GST_OBJECT_UNLOCK (src); -} - -static gint -gst_cdda_base_src_get_track_from_sector (GstCddaBaseSrc * src, gint sector) -{ - gint i; - - for (i = 0; i < src->num_tracks; ++i) { - if (sector >= src->tracks[i].start && sector <= src->tracks[i].end) - return i; - } - return -1; -} - -static const GstQueryType * -gst_cdda_base_src_get_query_types (GstPad * pad) -{ - static const GstQueryType src_query_types[] = { - GST_QUERY_DURATION, - GST_QUERY_POSITION, - GST_QUERY_CONVERT, - 0 - }; - - return src_query_types; -} - -static gboolean -gst_cdda_base_src_convert (GstCddaBaseSrc * src, GstFormat src_format, - gint64 src_val, GstFormat dest_format, gint64 * dest_val) -{ - gboolean started; - - GST_LOG_OBJECT (src, "converting value %" G_GINT64_FORMAT " from %s into %s", - src_val, gst_format_get_name (src_format), - gst_format_get_name (dest_format)); - - if (src_format == dest_format) { - *dest_val = src_val; - return TRUE; - } - - started = GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED); - - if (src_format == track_format) { - if (!started) - goto not_started; - if (src_val < 0 || src_val >= src->num_tracks) { - GST_DEBUG_OBJECT (src, "track number %d out of bounds", (gint) src_val); - goto wrong_value; - } - src_format = GST_FORMAT_DEFAULT; - src_val = src->tracks[src_val].start * SAMPLES_PER_SECTOR; - } else if (src_format == sector_format) { - src_format = GST_FORMAT_DEFAULT; - src_val = src_val * SAMPLES_PER_SECTOR; - } - - if (src_format == dest_format) { - *dest_val = src_val; - goto done; - } - - switch (src_format) { - case GST_FORMAT_BYTES: - /* convert to samples (4 bytes per sample) */ - src_val = src_val >> 2; - /* fallthrough */ - case GST_FORMAT_DEFAULT:{ - switch (dest_format) { - case GST_FORMAT_BYTES:{ - if (src_val < 0) { - GST_DEBUG_OBJECT (src, "sample source value negative"); - goto wrong_value; - } - *dest_val = src_val << 2; /* 4 bytes per sample */ - break; - } - case GST_FORMAT_TIME:{ - *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, 44100); - break; - } - default:{ - gint64 sector = src_val / SAMPLES_PER_SECTOR; - - if (dest_format == sector_format) { - *dest_val = sector; - } else if (dest_format == track_format) { - if (!started) - goto not_started; - *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector); - } else { - goto unknown_format; - } - break; - } - } - break; - } - case GST_FORMAT_TIME:{ - gint64 sample_offset; - - if (src_val == GST_CLOCK_TIME_NONE) { - GST_DEBUG_OBJECT (src, "source time value invalid"); - goto wrong_value; - } - - sample_offset = gst_util_uint64_scale_int (src_val, 44100, GST_SECOND); - switch (dest_format) { - case GST_FORMAT_BYTES:{ - *dest_val = sample_offset << 2; /* 4 bytes per sample */ - break; - } - case GST_FORMAT_DEFAULT:{ - *dest_val = sample_offset; - break; - } - default:{ - gint64 sector = sample_offset / SAMPLES_PER_SECTOR; - - if (dest_format == sector_format) { - *dest_val = sector; - } else if (dest_format == track_format) { - if (!started) - goto not_started; - *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector); - } else { - goto unknown_format; - } - break; - } - } - break; - } - default:{ - goto unknown_format; - } - } - -done: - { - GST_LOG_OBJECT (src, "returning %" G_GINT64_FORMAT, *dest_val); - return TRUE; - } - -unknown_format: - { - GST_DEBUG_OBJECT (src, "conversion failed: %s", "unsupported format"); - return FALSE; - } - -wrong_value: - { - GST_DEBUG_OBJECT (src, "conversion failed: %s", - "source value not within allowed range"); - return FALSE; - } - -not_started: - { - GST_DEBUG_OBJECT (src, "conversion failed: %s", - "cannot do this conversion, device not open"); - return FALSE; - } -} - -static gboolean -gst_cdda_base_src_query (GstBaseSrc * basesrc, GstQuery * query) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc); - gboolean started; - - started = GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED); - - GST_LOG_OBJECT (src, "handling %s query", - gst_query_type_get_name (GST_QUERY_TYPE (query))); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_DURATION:{ - GstFormat dest_format; - gint64 dest_val; - guint sectors; - - gst_query_parse_duration (query, &dest_format, NULL); - - if (!started) - return FALSE; - - g_assert (src->tracks != NULL); - - if (dest_format == track_format) { - GST_LOG_OBJECT (src, "duration: %d tracks", src->num_tracks); - gst_query_set_duration (query, track_format, src->num_tracks); - return TRUE; - } - - if (src->cur_track < 0 || src->cur_track >= src->num_tracks) - return FALSE; - - if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) { - sectors = src->tracks[src->cur_track].end - - src->tracks[src->cur_track].start + 1; - } else { - sectors = src->tracks[src->num_tracks - 1].end - - src->tracks[0].start + 1; - } - - /* ... and convert into final format */ - if (!gst_cdda_base_src_convert (src, sector_format, sectors, - dest_format, &dest_val)) { - return FALSE; - } - - gst_query_set_duration (query, dest_format, dest_val); - - GST_LOG ("duration: %u sectors, %" G_GINT64_FORMAT " in format %s", - sectors, dest_val, gst_format_get_name (dest_format)); - break; - } - case GST_QUERY_POSITION:{ - GstFormat dest_format; - gint64 pos_sector; - gint64 dest_val; - - gst_query_parse_position (query, &dest_format, NULL); - - if (!started) - return FALSE; - - g_assert (src->tracks != NULL); - - if (dest_format == track_format) { - GST_LOG_OBJECT (src, "position: track %d", src->cur_track); - gst_query_set_position (query, track_format, src->cur_track); - return TRUE; - } - - if (src->cur_track < 0 || src->cur_track >= src->num_tracks) - return FALSE; - - if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) { - pos_sector = src->cur_sector - src->tracks[src->cur_track].start; - } else { - pos_sector = src->cur_sector - src->tracks[0].start; - } - - if (!gst_cdda_base_src_convert (src, sector_format, pos_sector, - dest_format, &dest_val)) { - return FALSE; - } - - gst_query_set_position (query, dest_format, dest_val); - - GST_LOG ("position: sector %u, %" G_GINT64_FORMAT " in format %s", - (guint) pos_sector, dest_val, gst_format_get_name (dest_format)); - break; - } - case GST_QUERY_CONVERT:{ - GstFormat src_format, dest_format; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_format, &src_val, &dest_format, - NULL); - - if (!gst_cdda_base_src_convert (src, src_format, src_val, dest_format, - &dest_val)) { - return FALSE; - } - - gst_query_set_convert (query, src_format, src_val, dest_format, dest_val); - break; - } - default:{ - GST_DEBUG_OBJECT (src, "unhandled query, chaining up to parent class"); - return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query); - } - } - - return TRUE; -} - -static gboolean -gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc) -{ - return TRUE; -} - -static gboolean -gst_cdda_base_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc); - gint64 seek_sector; - - GST_DEBUG_OBJECT (src, "segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, - GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop)); - - if (!gst_cdda_base_src_convert (src, GST_FORMAT_TIME, segment->start, - sector_format, &seek_sector)) { - GST_WARNING_OBJECT (src, "conversion failed"); - return FALSE; - } - - /* we should only really be called when open */ - g_assert (src->cur_track >= 0 && src->cur_track < src->num_tracks); - - switch (src->mode) { - case GST_CDDA_BASE_SRC_MODE_NORMAL: - seek_sector += src->tracks[src->cur_track].start; - break; - case GST_CDDA_BASE_SRC_MODE_CONTINUOUS: - seek_sector += src->tracks[0].start; - break; - default: - g_return_val_if_reached (FALSE); - } - - src->cur_sector = (gint) seek_sector; - - GST_DEBUG_OBJECT (src, "seek'd to sector %d", src->cur_sector); - - return TRUE; -} - -static gboolean -gst_cdda_base_src_handle_track_seek (GstCddaBaseSrc * src, gdouble rate, - GstSeekFlags flags, GstSeekType start_type, gint64 start, - GstSeekType stop_type, gint64 stop) -{ - GstBaseSrc *basesrc = GST_BASE_SRC (src); - GstEvent *event; - - if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) { - gint64 start_time = -1; - gint64 stop_time = -1; - - if (src->mode != GST_CDDA_BASE_SRC_MODE_CONTINUOUS) { - GST_DEBUG_OBJECT (src, "segment seek in track format is only " - "supported in CONTINUOUS mode, not in mode %d", src->mode); - return FALSE; - } - - switch (start_type) { - case GST_SEEK_TYPE_SET: - if (!gst_cdda_base_src_convert (src, track_format, start, - GST_FORMAT_TIME, &start_time)) { - GST_DEBUG_OBJECT (src, "cannot convert track %d to time", - (gint) start); - return FALSE; - } - break; - case GST_SEEK_TYPE_END: - if (!gst_cdda_base_src_convert (src, track_format, - src->num_tracks - start - 1, GST_FORMAT_TIME, &start_time)) { - GST_DEBUG_OBJECT (src, "cannot convert track %d to time", - (gint) start); - return FALSE; - } - start_type = GST_SEEK_TYPE_SET; - break; - case GST_SEEK_TYPE_NONE: - start_time = -1; - break; - default: - g_return_val_if_reached (FALSE); - } - - switch (stop_type) { - case GST_SEEK_TYPE_SET: - if (!gst_cdda_base_src_convert (src, track_format, stop, - GST_FORMAT_TIME, &stop_time)) { - GST_DEBUG_OBJECT (src, "cannot convert track %d to time", - (gint) stop); - return FALSE; - } - break; - case GST_SEEK_TYPE_END: - if (!gst_cdda_base_src_convert (src, track_format, - src->num_tracks - stop - 1, GST_FORMAT_TIME, &stop_time)) { - GST_DEBUG_OBJECT (src, "cannot convert track %d to time", - (gint) stop); - return FALSE; - } - stop_type = GST_SEEK_TYPE_SET; - break; - case GST_SEEK_TYPE_NONE: - stop_time = -1; - break; - default: - g_return_val_if_reached (FALSE); - } - - GST_LOG_OBJECT (src, "seek segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, - GST_TIME_ARGS (start_time), GST_TIME_ARGS (stop_time)); - - /* send fake segment seek event in TIME format to - * base class, which will hopefully handle the rest */ - - event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type, - start_time, stop_type, stop_time); - - return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event); - } - - /* not a segment seek */ - - if (start_type == GST_SEEK_TYPE_NONE) { - GST_LOG_OBJECT (src, "start seek type is NONE, nothing to do"); - return TRUE; - } - - if (stop_type != GST_SEEK_TYPE_NONE) { - GST_WARNING_OBJECT (src, "ignoring stop seek type (expected NONE)"); - } - - if (start < 0 || start >= src->num_tracks) { - GST_DEBUG_OBJECT (src, "invalid track %" G_GINT64_FORMAT, start); - return FALSE; - } - - GST_DEBUG_OBJECT (src, "seeking to track %" G_GINT64_FORMAT, start + 1); - - src->cur_sector = src->tracks[start].start; - GST_DEBUG_OBJECT (src, "starting at sector %d", src->cur_sector); - - if (src->cur_track != start) { - src->cur_track = (gint) start; - src->uri_track = -1; - src->prev_track = -1; - - gst_cdda_base_src_update_duration (src); - } else { - GST_DEBUG_OBJECT (src, "is current track, just seeking back to start"); - } - - /* send fake segment seek event in TIME format to - * base class (so we get a newsegment etc.) */ - event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, - GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1); - - return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event); -} - -static gboolean -gst_cdda_base_src_handle_event (GstBaseSrc * basesrc, GstEvent * event) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc); - gboolean ret = FALSE; - - GST_LOG_OBJECT (src, "handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK:{ - GstSeekType start_type, stop_type; - GstSeekFlags flags; - GstFormat format; - gdouble rate; - gint64 start, stop; - - if (!GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED)) { - GST_DEBUG_OBJECT (src, "seek failed: device not open"); - break; - } - - gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, - &stop_type, &stop); - - if (format == sector_format) { - GST_DEBUG_OBJECT (src, "seek in sector format not supported"); - break; - } - - if (format == track_format) { - ret = gst_cdda_base_src_handle_track_seek (src, rate, flags, - start_type, start, stop_type, stop); - } else { - GST_LOG_OBJECT (src, "let base class handle seek in %s format", - gst_format_get_name (format)); - event = gst_event_ref (event); - ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event); - } - break; - } - default:{ - GST_LOG_OBJECT (src, "let base class handle event"); - ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event); - break; - } - } - - return ret; -} - -static GstURIType -gst_cdda_base_src_uri_get_type (void) -{ - return GST_URI_SRC; -} - -static gchar ** -gst_cdda_base_src_uri_get_protocols (void) -{ - static gchar *protocols[] = { "cdda", NULL }; - - return protocols; -} - -static const gchar * -gst_cdda_base_src_uri_get_uri (GstURIHandler * handler) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler); - - GST_OBJECT_LOCK (src); - - g_free (src->uri); - - if (GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED)) { - src->uri = g_strdup_printf ("cdda://%d", src->uri_track); - } else { - src->uri = g_strdup ("cdda://1"); - } - - GST_OBJECT_UNLOCK (src); - - return src->uri; -} - -/* Note: gst_element_make_from_uri() might call us with just 'cdda://' as - * URI and expects us to return TRUE then (and this might be in any state) */ - -static gboolean -gst_cdda_base_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler); - gchar *protocol, *location; - - GST_OBJECT_LOCK (src); - - protocol = gst_uri_get_protocol (uri); - if (!protocol || strcmp (protocol, "cdda") != 0) { - g_free (protocol); - goto failed; - } - g_free (protocol); - - location = gst_uri_get_location (uri); - if (location == NULL || *location == '\0') { - g_free (location); - location = g_strdup ("1"); - } - - src->uri_track = strtol (location, NULL, 10); - g_free (location); - - if (src->uri_track == 0) - goto failed; - - if (src->num_tracks > 0 - && src->tracks != NULL && src->uri_track > src->num_tracks) - goto failed; - - if (src->uri_track > 0 && src->tracks != NULL) { - GST_OBJECT_UNLOCK (src); - - gst_pad_send_event (GST_BASE_SRC_PAD (src), - gst_event_new_seek (1.0, track_format, GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, src->uri_track - 1, GST_SEEK_TYPE_NONE, -1)); - } else { - /* seek will be done in start() */ - GST_OBJECT_UNLOCK (src); - } - - GST_LOG_OBJECT (handler, "successfully handled uri '%s'", uri); - - return TRUE; - -failed: - { - GST_OBJECT_UNLOCK (src); - GST_DEBUG_OBJECT (src, "cannot handle URI '%s'", uri); - return FALSE; - } -} - -static void -gst_cdda_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_cdda_base_src_uri_get_type; - iface->get_uri = gst_cdda_base_src_uri_get_uri; - iface->set_uri = gst_cdda_base_src_uri_set_uri; - iface->get_protocols = gst_cdda_base_src_uri_get_protocols; -} - -static void -gst_cdda_base_src_setup_interfaces (GType type) -{ - static const GInterfaceInfo urihandler_info = { - gst_cdda_base_src_uri_handler_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); -} - -/** - * gst_cdda_base_src_add_track: - * @src: a #GstCddaBaseSrc - * @track: address of #GstCddaBaseSrcTrack to add - * - * CDDA sources use this function from their start vfunc to announce the - * available data and audio tracks to the base source class. The caller - * should allocate @track on the stack, the base source will do a shallow - * copy of the structure (and take ownership of the taglist if there is one). - * - * Returns: FALSE on error, otherwise TRUE. - */ - -gboolean -gst_cdda_base_src_add_track (GstCddaBaseSrc * src, GstCddaBaseSrcTrack * track) -{ - g_return_val_if_fail (GST_IS_CDDA_BASE_SRC (src), FALSE); - g_return_val_if_fail (track != NULL, FALSE); - g_return_val_if_fail (track->num > 0, FALSE); - - GST_DEBUG_OBJECT (src, "adding track %2u (%2u) [%6u-%6u] [%5s], tags: %" - GST_PTR_FORMAT, src->num_tracks + 1, track->num, track->start, - track->end, (track->is_audio) ? "AUDIO" : "DATA ", track->tags); - - if (src->num_tracks > 0) { - guint end_of_previous_track = src->tracks[src->num_tracks - 1].end; - - if (track->start <= end_of_previous_track) { - GST_WARNING ("track %2u overlaps with previous tracks", track->num); - return FALSE; - } - } - - GST_OBJECT_LOCK (src); - - ++src->num_tracks; - src->tracks = g_renew (GstCddaBaseSrcTrack, src->tracks, src->num_tracks); - src->tracks[src->num_tracks - 1] = *track; - - GST_OBJECT_UNLOCK (src); - - return TRUE; -} - -static void -gst_cdda_base_src_update_duration (GstCddaBaseSrc * src) -{ - GstBaseSrc *basesrc; - GstFormat format; - gint64 duration; - - basesrc = GST_BASE_SRC (src); - - format = GST_FORMAT_TIME; - if (gst_pad_query_duration (GST_BASE_SRC_PAD (src), &format, &duration)) { - gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, duration); - } else { - gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, -1); - duration = GST_CLOCK_TIME_NONE; - } - - gst_element_post_message (GST_ELEMENT (src), - gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_TIME, -1)); - - GST_LOG_OBJECT (src, "duration updated to %" GST_TIME_FORMAT, - GST_TIME_ARGS (duration)); -} - -#define CD_MSF_OFFSET 150 - -/* the cddb hash function */ -static guint -cddb_sum (gint n) -{ - guint ret; - - ret = 0; - while (n > 0) { - ret += (n % 10); - n /= 10; - } - return ret; -} - -#include "sha1.h" - -static void -gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src) -{ - GString *s; - SHA_INFO sha; - guchar digest[20]; - gchar *ptr; - gchar tmp[9]; - gulong i; - guint leadout_sector; - - s = g_string_new (NULL); - - leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET; - - /* generate SHA digest */ - sha_init (&sha); - g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num); - g_string_append_printf (s, "%02X", src->tracks[0].num); - sha_update (&sha, (SHA_BYTE *) tmp, 2); - - g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num); - g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num); - sha_update (&sha, (SHA_BYTE *) tmp, 2); - - g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector); - g_string_append_printf (s, " %08X", leadout_sector); - sha_update (&sha, (SHA_BYTE *) tmp, 8); - - for (i = 0; i < 99; i++) { - if (i < src->num_tracks) { - guint frame_offset = src->tracks[i].start + CD_MSF_OFFSET; - - g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset); - g_string_append_printf (s, " %08X", frame_offset); - sha_update (&sha, (SHA_BYTE *) tmp, 8); - } else { - sha_update (&sha, (SHA_BYTE *) "00000000", 8); - } - } - sha_final (digest, &sha); - - /* re-encode to base64 */ - ptr = g_base64_encode (digest, 20); - i = strlen (ptr); - - g_assert (i < sizeof (src->mb_discid) + 1); - memcpy (src->mb_discid, ptr, i); - src->mb_discid[i] = '\0'; - free (ptr); - - /* Replace '/', '+' and '=' by '_', '.' and '-' as specified on - * http://musicbrainz.org/doc/DiscIDCalculation - */ - for (ptr = src->mb_discid; *ptr != '\0'; ptr++) { - if (*ptr == '/') - *ptr = '_'; - else if (*ptr == '+') - *ptr = '.'; - else if (*ptr == '=') - *ptr = '-'; - } - - GST_DEBUG_OBJECT (src, "musicbrainz-discid = %s", src->mb_discid); - GST_DEBUG_OBJECT (src, "musicbrainz-discid-full = %s", s->str); - - gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE, - GST_TAG_CDDA_MUSICBRAINZ_DISCID, src->mb_discid, - GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL, s->str, NULL); - - g_string_free (s, TRUE); -} - -static void -lba_to_msf (guint sector, guint * p_m, guint * p_s, guint * p_f, guint * p_secs) -{ - guint m, s, f; - - m = sector / SECTORS_PER_MINUTE; - sector = sector % SECTORS_PER_MINUTE; - s = sector / SECTORS_PER_SECOND; - f = sector % SECTORS_PER_SECOND; - - if (p_m) - *p_m = m; - if (p_s) - *p_s = s; - if (p_f) - *p_f = f; - if (p_secs) - *p_secs = s + (m * 60); -} - -static void -gst_cdda_base_src_calculate_cddb_id (GstCddaBaseSrc * src) -{ - GString *s; - guint first_sector = 0, last_sector = 0; - guint start_secs, end_secs, secs, len_secs; - guint total_secs, num_audio_tracks; - guint id, t, i; - - id = 0; - total_secs = 0; - num_audio_tracks = 0; - - /* FIXME: do we use offsets and duration of ALL tracks (data + audio) - * for the CDDB ID calculation, or only audio tracks? */ - for (i = 0; i < src->num_tracks; ++i) { - if (1) { /* src->tracks[i].is_audio) { */ - if (num_audio_tracks == 0) { - first_sector = src->tracks[i].start + CD_MSF_OFFSET; - } - last_sector = src->tracks[i].end + CD_MSF_OFFSET + 1; - ++num_audio_tracks; - - lba_to_msf (src->tracks[i].start + CD_MSF_OFFSET, NULL, NULL, NULL, - &secs); - - len_secs = (src->tracks[i].end - src->tracks[i].start + 1) / 75; - - GST_DEBUG_OBJECT (src, "track %02u: lsn %6u (%02u:%02u), " - "length: %u seconds (%02u:%02u)", - num_audio_tracks, src->tracks[i].start + CD_MSF_OFFSET, - secs / 60, secs % 60, len_secs, len_secs / 60, len_secs % 60); - - id += cddb_sum (secs); - total_secs += len_secs; - } - } - - /* first_sector = src->tracks[0].start + CD_MSF_OFFSET; */ - lba_to_msf (first_sector, NULL, NULL, NULL, &start_secs); - - /* last_sector = src->tracks[src->num_tracks-1].end + CD_MSF_OFFSET; */ - lba_to_msf (last_sector, NULL, NULL, NULL, &end_secs); - - GST_DEBUG_OBJECT (src, "first_sector = %u = %u secs (%02u:%02u)", - first_sector, start_secs, start_secs / 60, start_secs % 60); - GST_DEBUG_OBJECT (src, "last_sector = %u = %u secs (%02u:%02u)", - last_sector, end_secs, end_secs / 60, end_secs % 60); - - t = end_secs - start_secs; - - GST_DEBUG_OBJECT (src, "total length = %u secs (%02u:%02u), added title " - "lengths = %u seconds (%02u:%02u)", t, t / 60, t % 60, total_secs, - total_secs / 60, total_secs % 60); - - src->discid = ((id % 0xff) << 24 | t << 8 | num_audio_tracks); - - s = g_string_new (NULL); - g_string_append_printf (s, "%08x", src->discid); - - gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE, - GST_TAG_CDDA_CDDB_DISCID, s->str, NULL); - - g_string_append_printf (s, " %u", src->num_tracks); - for (i = 0; i < src->num_tracks; ++i) { - g_string_append_printf (s, " %u", src->tracks[i].start + CD_MSF_OFFSET); - } - g_string_append_printf (s, " %u", t); - - gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE, - GST_TAG_CDDA_CDDB_DISCID_FULL, s->str, NULL); - - GST_DEBUG_OBJECT (src, "cddb discid = %s", s->str); - - g_string_free (s, TRUE); -} - -static void -gst_cdda_base_src_add_tags (GstCddaBaseSrc * src) -{ - gint i; - - /* fill in details for each track */ - for (i = 0; i < src->num_tracks; ++i) { - gint64 duration; - guint num_sectors; - - if (src->tracks[i].tags == NULL) - src->tracks[i].tags = gst_tag_list_new (); - - num_sectors = src->tracks[i].end - src->tracks[i].start + 1; - gst_cdda_base_src_convert (src, sector_format, num_sectors, - GST_FORMAT_TIME, &duration); - - gst_tag_list_add (src->tracks[i].tags, - GST_TAG_MERGE_REPLACE, - GST_TAG_TRACK_NUMBER, i + 1, - GST_TAG_TRACK_COUNT, src->num_tracks, GST_TAG_DURATION, duration, NULL); - } - - /* now fill in per-album tags and include each track's tags - * in the album tags, so that interested parties can retrieve - * the relevant details for each track in one go */ - - /* /////////////////////////////// FIXME should we rather insert num_tracks - * tags by the name of 'track-tags' and have the caller use - * gst_tag_list_get_value_index() rather than use tag names incl. - * the track number ?? *//////////////////////////////////////// - - gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE, - GST_TAG_TRACK_COUNT, src->num_tracks, NULL); -#if 0 - for (i = 0; i < src->num_tracks; ++i) { - gst_tag_list_add (src->tags, GST_TAG_MERGE_APPEND, - GST_TAG_CDDA_TRACK_TAGS, src->tracks[i].tags, NULL); - } -#endif - - GST_DEBUG ("src->tags = %" GST_PTR_FORMAT, src->tags); -} - -static void -gst_cdda_base_src_add_index_associations (GstCddaBaseSrc * src) -{ - gint i; - - for (i = 0; i < src->num_tracks; i++) { - gint64 sector; - - sector = src->tracks[i].start; - gst_index_add_association (src->index, src->index_id, GST_ASSOCIATION_FLAG_KEY_UNIT, track_format, i, /* here we count from 0 */ - sector_format, sector, - GST_FORMAT_TIME, - (gint64) (((CD_FRAMESIZE_RAW >> 2) * sector * GST_SECOND) / 44100), - GST_FORMAT_BYTES, (gint64) (sector << 2), GST_FORMAT_DEFAULT, - (gint64) ((CD_FRAMESIZE_RAW >> 2) * sector), NULL); - } -} - -static void -gst_cdda_base_src_set_index (GstElement * element, GstIndex * index) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element); - - src->index = index; - - gst_index_get_writer_id (index, GST_OBJECT (src), &src->index_id); - gst_index_add_format (index, src->index_id, track_format); - gst_index_add_format (index, src->index_id, sector_format); -} - - -static GstIndex * -gst_cdda_base_src_get_index (GstElement * element) -{ - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element); - - return src->index; -} - -static gint -gst_cdda_base_src_track_sort_func (gconstpointer a, gconstpointer b, - gpointer foo) -{ - GstCddaBaseSrcTrack *track_a = ((GstCddaBaseSrcTrack *) a); - GstCddaBaseSrcTrack *track_b = ((GstCddaBaseSrcTrack *) b); - - /* sort data tracks to the end, and audio tracks by track number */ - if (track_a->is_audio == track_b->is_audio) - return (gint) track_a->num - (gint) track_b->num; - - if (track_a->is_audio) { - return -1; - } else { - return 1; - } -} - -static gboolean -gst_cdda_base_src_start (GstBaseSrc * basesrc) -{ - GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc); - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc); - gboolean ret; - gchar *device = NULL; - - src->discid = 0; - src->mb_discid[0] = '\0'; - - g_assert (klass->open != NULL); - - if (src->device != NULL) { - device = g_strdup (src->device); - } else if (klass->get_default_device != NULL) { - device = klass->get_default_device (src); - } - - if (device == NULL) - device = g_strdup (DEFAULT_DEVICE); - - GST_LOG_OBJECT (basesrc, "opening device %s", device); - - src->tags = gst_tag_list_new (); - - ret = klass->open (src, device); - g_free (device); - device = NULL; - - if (!ret) { - GST_DEBUG_OBJECT (basesrc, "failed to open device"); - /* subclass (should have) posted an error message with the details */ - gst_cdda_base_src_stop (basesrc); - return FALSE; - } - - if (src->num_tracks == 0 || src->tracks == NULL) { - GST_DEBUG_OBJECT (src, "no tracks"); - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, - (_("This CD has no audio tracks")), (NULL)); - gst_cdda_base_src_stop (basesrc); - return FALSE; - } - - /* need to calculate disc IDs before we ditch the data tracks */ - gst_cdda_base_src_calculate_cddb_id (src); - gst_cddabasesrc_calculate_musicbrainz_discid (src); - -#if 0 - /* adjust sector offsets if necessary */ - if (src->toc_bias) { - src->toc_offset -= src->tracks[0].start; - } - for (i = 0; i < src->num_tracks; ++i) { - src->tracks[i].start += src->toc_offset; - src->tracks[i].end += src->toc_offset; - } -#endif - - /* now that we calculated the various disc IDs, - * sort the data tracks to end and ignore them */ - src->num_all_tracks = src->num_tracks; - - g_qsort_with_data (src->tracks, src->num_tracks, - sizeof (GstCddaBaseSrcTrack), gst_cdda_base_src_track_sort_func, NULL); - - while (src->num_tracks > 0 && !src->tracks[src->num_tracks - 1].is_audio) - --src->num_tracks; - - if (src->num_tracks == 0) { - GST_DEBUG_OBJECT (src, "no audio tracks"); - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, - (_("This CD has no audio tracks")), (NULL)); - gst_cdda_base_src_stop (basesrc); - return FALSE; - } - - gst_cdda_base_src_add_tags (src); - - if (src->index && GST_INDEX_IS_WRITABLE (src->index)) - gst_cdda_base_src_add_index_associations (src); - - src->cur_track = 0; - src->prev_track = -1; - - if (src->uri_track > 0 && src->uri_track <= src->num_tracks) { - GST_LOG_OBJECT (src, "seek to track %d", src->uri_track); - src->cur_track = src->uri_track - 1; - src->uri_track = -1; - src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL; - } - - src->cur_sector = src->tracks[src->cur_track].start; - GST_LOG_OBJECT (src, "starting at sector %d", src->cur_sector); - - gst_cdda_base_src_update_duration (src); - - return TRUE; -} - -static void -gst_cdda_base_src_clear_tracks (GstCddaBaseSrc * src) -{ - if (src->tracks != NULL) { - gint i; - - for (i = 0; i < src->num_all_tracks; ++i) { - if (src->tracks[i].tags) - gst_tag_list_free (src->tracks[i].tags); - } - - g_free (src->tracks); - src->tracks = NULL; - } - src->num_tracks = 0; - src->num_all_tracks = 0; -} - -static gboolean -gst_cdda_base_src_stop (GstBaseSrc * basesrc) -{ - GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc); - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc); - - g_assert (klass->close != NULL); - - klass->close (src); - - gst_cdda_base_src_clear_tracks (src); - - if (src->tags) { - gst_tag_list_free (src->tags); - src->tags = NULL; - } - - src->prev_track = -1; - src->cur_track = -1; - - return TRUE; -} - - -static GstFlowReturn -gst_cdda_base_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer) -{ - GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (pushsrc); - GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (pushsrc); - GstBuffer *buf; - GstFormat format; - gboolean eos; - - GstClockTime position = GST_CLOCK_TIME_NONE; - GstClockTime duration = GST_CLOCK_TIME_NONE; - gint64 qry_position; - - g_assert (klass->read_sector != NULL); - - switch (src->mode) { - case GST_CDDA_BASE_SRC_MODE_NORMAL: - eos = (src->cur_sector > src->tracks[src->cur_track].end); - break; - case GST_CDDA_BASE_SRC_MODE_CONTINUOUS: - eos = (src->cur_sector > src->tracks[src->num_tracks - 1].end); - src->cur_track = gst_cdda_base_src_get_track_from_sector (src, - src->cur_sector); - break; - default: - g_return_val_if_reached (GST_FLOW_ERROR); - } - - if (eos) { - src->prev_track = -1; - GST_DEBUG_OBJECT (src, "EOS at sector %d, cur_track=%d, mode=%d", - src->cur_sector, src->cur_track, src->mode); - /* base class will send EOS for us */ - return GST_FLOW_UNEXPECTED; - } - - if (src->prev_track != src->cur_track) { - GstTagList *tags; - - tags = gst_tag_list_merge (src->tags, src->tracks[src->cur_track].tags, - GST_TAG_MERGE_REPLACE); - GST_LOG_OBJECT (src, "announcing tags: %" GST_PTR_FORMAT, tags); - gst_element_found_tags_for_pad (GST_ELEMENT (src), - GST_BASE_SRC_PAD (src), tags); - src->prev_track = src->cur_track; - - gst_cdda_base_src_update_duration (src); - - g_object_notify (G_OBJECT (src), "track"); - } - - GST_LOG_OBJECT (src, "asking for sector %u", src->cur_sector); - - buf = klass->read_sector (src, src->cur_sector); - - if (buf == NULL) { - GST_WARNING_OBJECT (src, "failed to read sector %u", src->cur_sector); - return GST_FLOW_ERROR; - } - - if (GST_BUFFER_CAPS (buf) == NULL) { - gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src))); - } - - format = GST_FORMAT_TIME; - if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &qry_position)) { - gint64 next_ts = 0; - - position = (GstClockTime) qry_position; - - ++src->cur_sector; - if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &next_ts)) { - duration = (GstClockTime) (next_ts - qry_position); - } - --src->cur_sector; - } - - /* fallback duration: 4 bytes per sample, 44100 samples per second */ - if (duration == GST_CLOCK_TIME_NONE) { - duration = gst_util_uint64_scale_int (GST_BUFFER_SIZE (buf) >> 2, - GST_SECOND, 44100); - } - - GST_BUFFER_TIMESTAMP (buf) = position; - GST_BUFFER_DURATION (buf) = duration; - - GST_LOG_OBJECT (src, "pushing sector %d with timestamp %" GST_TIME_FORMAT, - src->cur_sector, GST_TIME_ARGS (position)); - - ++src->cur_sector; - - *buffer = buf; - - return GST_FLOW_OK; -} diff --git a/gst-libs/gst/rtp/gst-plugins-base-rtcp-feedback.patch b/gst-libs/gst/rtp/gst-plugins-base-rtcp-feedback.patch deleted file mode 100644 index ad50816..0000000 --- a/gst-libs/gst/rtp/gst-plugins-base-rtcp-feedback.patch +++ /dev/null @@ -1,224 +0,0 @@ -diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c -index ab77c8a..fb35a92 100644 ---- a/gst-libs/gst/rtp/gstrtcpbuffer.c -+++ b/gst-libs/gst/rtp/gstrtcpbuffer.c -@@ -449,6 +449,11 @@ gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type, - case GST_RTCP_TYPE_APP: - len = 12; - break; -+ case GST_RTCP_TYPE_RTPFB: -+ len = 12; -+ break; -+ case GST_RTCP_TYPE_PSFB: -+ len = 12; - default: - goto unknown_type; - } -@@ -1637,6 +1642,147 @@ no_space: - } - - /** -+ * gst_rtcp_packet_fb_get_sender_ssrc: -+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket -+ * -+ * Get the sender SSRC field of the RTPFB or PSFB @packet. -+ * -+ * Returns: the sender SSRC. -+ */ -+guint32 -+gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket * packet) -+{ -+ guint8 *data; -+ guint32 ssrc; -+ -+ g_return_val_if_fail (packet != NULL, 0); -+ g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB || -+ packet->type == GST_RTCP_TYPE_PSFB), 0); -+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); -+ -+ data = GST_BUFFER_DATA (packet->buffer); -+ -+ /* skip header */ -+ data += packet->offset + 4; -+ ssrc = GST_READ_UINT32_BE (data); -+ -+ return ssrc; -+} -+ -+/** -+ * gst_rtcp_packet_fb_set_sender_ssrc: -+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket -+ * -+ * Set the sender SSRC field of the RTPFB or PSFB @packet. -+ */ -+void -+gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc) -+{ -+ guint8 *data; -+ -+ g_return_if_fail (packet != NULL); -+ g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB || -+ packet->type == GST_RTCP_TYPE_PSFB); -+ g_return_if_fail (GST_IS_BUFFER (packet->buffer)); -+ -+ data = GST_BUFFER_DATA (packet->buffer); -+ -+ /* skip header */ -+ data += packet->offset + 4; -+ GST_WRITE_UINT32_BE (data, ssrc); -+} -+ -+/** -+ * gst_rtcp_packet_fb_get_media_ssrc: -+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket -+ * -+ * Get the media SSRC field of the RTPFB or PSFB @packet. -+ * -+ * Returns: the media SSRC. -+ */ -+guint32 -+gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket * packet) -+{ -+ guint8 *data; -+ guint32 ssrc; -+ -+ g_return_val_if_fail (packet != NULL, 0); -+ g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB || -+ packet->type == GST_RTCP_TYPE_PSFB), 0); -+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); -+ -+ data = GST_BUFFER_DATA (packet->buffer); -+ -+ /* skip header and sender ssrc */ -+ data += packet->offset + 8; -+ ssrc = GST_READ_UINT32_BE (data); -+ -+ return ssrc; -+} -+ -+/** -+ * gst_rtcp_packet_fb_set_media_ssrc: -+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket -+ * -+ * Set the media SSRC field of the RTPFB or PSFB @packet. -+ */ -+void -+gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket *packet, guint32 ssrc) -+{ -+ guint8 *data; -+ -+ g_return_if_fail (packet != NULL); -+ g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB || -+ packet->type == GST_RTCP_TYPE_PSFB); -+ g_return_if_fail (GST_IS_BUFFER (packet->buffer)); -+ -+ data = GST_BUFFER_DATA (packet->buffer); -+ -+ /* skip header and sender ssrc */ -+ data += packet->offset + 8; -+ GST_WRITE_UINT32_BE (data, ssrc); -+} -+ -+/** -+ * gst_rtcp_packet_psfb_get_type: -+ * @packet: a valid PSFB #GstRTCPPacket -+ * -+ * Get the feedback message type of the PSFB @packet. -+ * -+ * Returns: The feedback message type. -+ */ -+GstRTCPPSFBType -+gst_rtcp_packet_psfb_get_type (GstRTCPPacket *packet) -+{ -+ g_return_val_if_fail (packet != NULL, GST_RTCP_PSFB_TYPE_INVALID); -+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_PSFB, -+ GST_RTCP_PSFB_TYPE_INVALID); -+ -+ return packet->count; -+} -+ -+/** -+ * gst_rtcp_packet_psfb_set_type: -+ * @packet: a valid PSFB #GstRTCPPacket -+ * @type: the #GstRTCPPSFBType to set -+ * -+ * Set the feedback message type of the PSFB @packet. -+ */ -+void -+gst_rtcp_packet_psfb_set_type (GstRTCPPacket *packet, GstRTCPPSFBType type) -+{ -+ guint8 *data; -+ -+ g_return_if_fail (packet != NULL); -+ g_return_if_fail (packet->type == GST_RTCP_TYPE_PSFB); -+ g_return_if_fail (GST_IS_BUFFER (packet->buffer)); -+ -+ data = GST_BUFFER_DATA (packet->buffer); -+ -+ data[packet->offset] = (data[packet->offset] & 0xE0) | type; -+} -+ -+/** - * gst_rtcp_ntp_to_unix: - * @ntptime: an NTP timestamp - * -diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h -index 9c908a8..bb247c9 100644 ---- a/gst-libs/gst/rtp/gstrtcpbuffer.h -+++ b/gst-libs/gst/rtp/gstrtcpbuffer.h -@@ -42,6 +42,8 @@ G_BEGIN_DECLS - * @GST_RTCP_TYPE_SDES: Source description - * @GST_RTCP_TYPE_BYE: Goodbye - * @GST_RTCP_TYPE_APP: Application defined -+ * @GST_RTCP_TYPE_RTPFB: Transport layer feedback -+ * @GST_RTCP_TYPE_PSFB: Payload-specific feedback - * - * Different RTCP packet types. - */ -@@ -52,9 +54,28 @@ typedef enum - GST_RTCP_TYPE_RR = 201, - GST_RTCP_TYPE_SDES = 202, - GST_RTCP_TYPE_BYE = 203, -- GST_RTCP_TYPE_APP = 204 -+ GST_RTCP_TYPE_APP = 204, -+ GST_RTCP_TYPE_RTPFB = 205, -+ GST_RTCP_TYPE_PSFB = 206 - } GstRTCPType; - -+/** -+ * GstRTCPPSFBType: -+ * @GST_RTCP_PSFB_TYPE_INVALID: Invalid type -+ * @GST_RTCP_PSFB_TYPE_PLI: Picture Loss Indication -+ * @GST_RTCP_PSFB_TYPE_SLI: Slice Loss Indication -+ * @GST_RTCP_PSFB_TYPE_RPSI: Reference Picture Selection Indication -+ * @GST_RTCP_PSFB_TYPE_AFB: Application layer Feedback -+ */ -+typedef enum -+{ -+ GST_RTCP_PSFB_TYPE_INVALID = 0, -+ GST_RTCP_PSFB_TYPE_PLI = 1, -+ GST_RTCP_PSFB_TYPE_SLI = 2, -+ GST_RTCP_PSFB_TYPE_RPSI = 3, -+ GST_RTCP_PSFB_TYPE_AFB = 15 -+} GstRTCPPSFBType; -+ - /** - * GstRTCPSDESType: - * @GST_RTCP_SDES_INVALID: Invalid SDES entry -@@ -232,6 +253,16 @@ guint8 gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket *packet); - gchar* gst_rtcp_packet_bye_get_reason (GstRTCPPacket *packet); - gboolean gst_rtcp_packet_bye_set_reason (GstRTCPPacket *packet, const gchar *reason); - -+/* feedback packets */ -+guint32 gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket *packet); -+void gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc); -+guint32 gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket *packet); -+void gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket *packet, guint32 ssrc); -+ -+/* psfb packets */ -+GstRTCPPSFBType gst_rtcp_packet_psfb_get_type (GstRTCPPacket *packet); -+void gst_rtcp_packet_psfb_set_type (GstRTCPPacket *packet, GstRTCPPSFBType type); -+ - /* helper functions */ - guint64 gst_rtcp_ntp_to_unix (guint64 ntptime); - guint64 gst_rtcp_unix_to_ntp (guint64 unixtime); diff --git a/gst-libs/gst/rtp/gstbasertppayload.c.orig b/gst-libs/gst/rtp/gstbasertppayload.c.orig deleted file mode 100644 index e1cc721..0000000 --- a/gst-libs/gst/rtp/gstbasertppayload.c.orig +++ /dev/null @@ -1,1040 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Wim Taymans - * - * 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 - */ - -/** - * SECTION:gstbasertppayload - * @short_description: Base class for RTP payloader - * - * - * - * Provides a base class for RTP payloaders - * - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include - -#include "gstbasertppayload.h" - -GST_DEBUG_CATEGORY_STATIC (basertppayload_debug); -#define GST_CAT_DEFAULT (basertppayload_debug) - -#define GST_BASE_RTP_PAYLOAD_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_PAYLOAD, GstBaseRTPPayloadPrivate)) - -struct _GstBaseRTPPayloadPrivate -{ - gboolean ts_offset_random; - gboolean seqnum_offset_random; - gboolean ssrc_random; - guint16 next_seqnum; - gboolean perfect_rtptime; - - gint64 prop_max_ptime; - gint64 caps_max_ptime; -}; - -/* BaseRTPPayload signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -/* FIXME 0.11, a better default is the Ethernet MTU of - * 1500 - sizeof(headers) as pointed out by marcelm in IRC: - * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives - * 1432 bytes or so. And that should be adjusted downward further for other - * encapsulations like PPPoE, so 1400 at most. - */ -#define DEFAULT_MTU 1400 -#define DEFAULT_PT 96 -#define DEFAULT_SSRC -1 -#define DEFAULT_TIMESTAMP_OFFSET -1 -#define DEFAULT_SEQNUM_OFFSET -1 -#define DEFAULT_MAX_PTIME -1 -#define DEFAULT_MIN_PTIME 0 -#define DEFAULT_PERFECT_RTPTIME TRUE -#define DEFAULT_PTIME_MULTIPLE 0 - -enum -{ - PROP_0, - PROP_MTU, - PROP_PT, - PROP_SSRC, - PROP_TIMESTAMP_OFFSET, - PROP_SEQNUM_OFFSET, - PROP_MAX_PTIME, - PROP_MIN_PTIME, - PROP_TIMESTAMP, - PROP_SEQNUM, - PROP_PERFECT_RTPTIME, - PROP_PTIME_MULTIPLE, - PROP_LAST -}; - -static void gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass); -static void gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass); -static void gst_basertppayload_init (GstBaseRTPPayload * basertppayload, - gpointer g_class); -static void gst_basertppayload_finalize (GObject * object); - -static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad); -static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_basertppayload_chain (GstPad * pad, - GstBuffer * buffer); - -static void gst_basertppayload_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_basertppayload_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstStateChangeReturn gst_basertppayload_change_state (GstElement * - element, GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -/* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */ - -GType -gst_basertppayload_get_type (void) -{ - static GType basertppayload_type = 0; - - if (!basertppayload_type) { - static const GTypeInfo basertppayload_info = { - sizeof (GstBaseRTPPayloadClass), - (GBaseInitFunc) gst_basertppayload_base_init, - NULL, - (GClassInitFunc) gst_basertppayload_class_init, - NULL, - NULL, - sizeof (GstBaseRTPPayload), - 0, - (GInstanceInitFunc) gst_basertppayload_init, - }; - - basertppayload_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload", - &basertppayload_info, G_TYPE_FLAG_ABSTRACT); - } - return basertppayload_type; -} - -static void -gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass) -{ -} - -static void -gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate)); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_basertppayload_finalize; - - gobject_class->set_property = gst_basertppayload_set_property; - gobject_class->get_property = gst_basertppayload_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU, - g_param_spec_uint ("mtu", "MTU", - "Maximum size of one packet", - 28, G_MAXUINT, DEFAULT_MTU, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT, - g_param_spec_uint ("pt", "payload type", - "The payload type of the packets", 0, 0x80, DEFAULT_PT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC, - g_param_spec_uint ("ssrc", "SSRC", - "The SSRC of the packets (default == random)", 0, G_MAXUINT32, - DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset", - "Timestamp Offset", - "Offset to add to all outgoing timestamps (default = random)", 0, - G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET, - g_param_spec_int ("seqnum-offset", "Sequence number Offset", - "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16, - DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME, - g_param_spec_int64 ("max-ptime", "Max packet time", - "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - -1, G_MAXINT64, DEFAULT_MAX_PTIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstBaseRTPAudioPayload:min-ptime: - * - * Minimum duration of the packet data in ns (can't go above MTU) - * - * Since: 0.10.13 - **/ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME, - g_param_spec_int64 ("min-ptime", "Min packet time", - "Minimum duration of the packet data in ns (can't go above MTU)", - 0, G_MAXINT64, DEFAULT_MIN_PTIME, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP, - g_param_spec_uint ("timestamp", "Timestamp", - "The RTP timestamp of the last processed packet", - 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM, - g_param_spec_uint ("seqnum", "Sequence number", - "The RTP sequence number of the last processed packet", - 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - /** - * GstBaseRTPAudioPayload:perfect-rtptime: - * - * Try to use the offset fields to generate perfect RTP timestamps. when this - * option is disabled, RTP timestamps are generated from the GStreamer - * timestamps, which could result in RTP timestamps that don't increment with - * the amount of data in the packet. - * - * Since: 0.10.25 - */ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PERFECT_RTPTIME, - g_param_spec_boolean ("perfect-rtptime", "Perfect RTP Time", - "Generate perfect RTP timestamps when possible", - DEFAULT_PERFECT_RTPTIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstBaseRTPAudioPayload:ptime-multiple: - * - * Force buffers to be multiples of this duration in ns (0 disables) - * - * Since: 0.10.29 - **/ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PTIME_MULTIPLE, - g_param_spec_int64 ("ptime-multiple", "Packet time multiple", - "Force buffers to be multiples of this duration in ns (0 disables)", - 0, G_MAXINT64, DEFAULT_PTIME_MULTIPLE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->change_state = gst_basertppayload_change_state; - - GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0, - "Base class for RTP Payloaders"); -} - -static void -gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class) -{ - GstPadTemplate *templ; - GstBaseRTPPayloadPrivate *priv; - - basertppayload->priv = priv = - GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload); - - templ = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); - g_return_if_fail (templ != NULL); - - basertppayload->srcpad = gst_pad_new_from_template (templ, "src"); - gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->srcpad); - - templ = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); - g_return_if_fail (templ != NULL); - - basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink"); - gst_pad_set_setcaps_function (basertppayload->sinkpad, - gst_basertppayload_sink_setcaps); - gst_pad_set_getcaps_function (basertppayload->sinkpad, - gst_basertppayload_sink_getcaps); - gst_pad_set_event_function (basertppayload->sinkpad, - gst_basertppayload_event); - gst_pad_set_chain_function (basertppayload->sinkpad, - gst_basertppayload_chain); - gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad); - - basertppayload->seq_rand = g_rand_new_with_seed (g_random_int ()); - basertppayload->ssrc_rand = g_rand_new_with_seed (g_random_int ()); - basertppayload->ts_rand = g_rand_new_with_seed (g_random_int ()); - - basertppayload->mtu = DEFAULT_MTU; - basertppayload->pt = DEFAULT_PT; - basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET; - basertppayload->ssrc = DEFAULT_SSRC; - basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET; - priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1); - priv->ts_offset_random = (basertppayload->ts_offset == -1); - priv->ssrc_random = (basertppayload->ssrc == -1); - - basertppayload->max_ptime = DEFAULT_MAX_PTIME; - basertppayload->min_ptime = DEFAULT_MIN_PTIME; - basertppayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME; - basertppayload->abidata.ABI.ptime_multiple = DEFAULT_PTIME_MULTIPLE; - - basertppayload->media = NULL; - basertppayload->encoding_name = NULL; - - basertppayload->clock_rate = 0; - - basertppayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME; - basertppayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME; -} - -static void -gst_basertppayload_finalize (GObject * object) -{ - GstBaseRTPPayload *basertppayload; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - - g_rand_free (basertppayload->seq_rand); - basertppayload->seq_rand = NULL; - g_rand_free (basertppayload->ssrc_rand); - basertppayload->ssrc_rand = NULL; - g_rand_free (basertppayload->ts_rand); - basertppayload->ts_rand = NULL; - - g_free (basertppayload->media); - basertppayload->media = NULL; - g_free (basertppayload->encoding_name); - basertppayload->encoding_name = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - gboolean ret = TRUE; - - GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps); - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->set_caps) - ret = basertppayload_class->set_caps (basertppayload, caps); - - gst_object_unref (basertppayload); - - return ret; -} - -static GstCaps * -gst_basertppayload_sink_getcaps (GstPad * pad) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - GstCaps *caps = NULL; - - GST_DEBUG_OBJECT (pad, "getting caps"); - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->get_caps) - caps = basertppayload_class->get_caps (basertppayload, pad); - - if (!caps) { - caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); - GST_DEBUG_OBJECT (pad, - "using pad template %p with caps %p %" GST_PTR_FORMAT, - GST_PAD_PAD_TEMPLATE (pad), caps, caps); - - caps = gst_caps_ref (caps); - } - - gst_object_unref (basertppayload); - - return caps; -} - -static gboolean -gst_basertppayload_event (GstPad * pad, GstEvent * event) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - gboolean res; - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (basertppayload_class->handle_event) { - res = basertppayload_class->handle_event (pad, event); - if (res) - goto done; - } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - res = gst_pad_event_default (pad, event); - break; - case GST_EVENT_FLUSH_STOP: - res = gst_pad_event_default (pad, event); - gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); - break; - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - gdouble rate; - GstFormat fmt; - gint64 start, stop, position; - - gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop, - &position); - gst_segment_set_newsegment (&basertppayload->segment, update, rate, fmt, - start, stop, position); - - /* fallthrough */ - } - default: - res = gst_pad_event_default (pad, event); - break; - } - -done: - gst_object_unref (basertppayload); - - return res; -} - - -static GstFlowReturn -gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadClass *basertppayload_class; - GstFlowReturn ret; - - basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad)); - basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload); - - if (!basertppayload_class->handle_buffer) - goto no_function; - - ret = basertppayload_class->handle_buffer (basertppayload, buffer); - - gst_object_unref (basertppayload); - - return ret; - - /* ERRORS */ -no_function: - { - GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL), - ("subclass did not implement handle_buffer function")); - gst_object_unref (basertppayload); - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } -} - -/** - * gst_basertppayload_set_options: - * @payload: a #GstBaseRTPPayload - * @media: the media type (typically "audio" or "video") - * @dynamic: if the payload type is dynamic - * @encoding_name: the encoding name - * @clock_rate: the clock rate of the media - * - * Set the rtp options of the payloader. These options will be set in the caps - * of the payloader. Subclasses must call this method before calling - * gst_basertppayload_push() or gst_basertppayload_set_outcaps(). - */ -void -gst_basertppayload_set_options (GstBaseRTPPayload * payload, - const gchar * media, gboolean dynamic, const gchar * encoding_name, - guint32 clock_rate) -{ - g_return_if_fail (payload != NULL); - g_return_if_fail (clock_rate != 0); - - g_free (payload->media); - payload->media = g_strdup (media); - payload->dynamic = dynamic; - g_free (payload->encoding_name); - payload->encoding_name = g_strdup (encoding_name); - payload->clock_rate = clock_rate; -} - -static gboolean -copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest) -{ - if (gst_value_is_fixed (value)) { - gst_structure_id_set_value (dest, field_id, value); - } - return TRUE; -} - -static void -update_max_ptime (GstBaseRTPPayload * basertppayload) -{ - if (basertppayload->priv->caps_max_ptime != -1 && - basertppayload->priv->prop_max_ptime != -1) - basertppayload->max_ptime = MIN (basertppayload->priv->caps_max_ptime, - basertppayload->priv->prop_max_ptime); - else if (basertppayload->priv->caps_max_ptime != -1) - basertppayload->max_ptime = basertppayload->priv->caps_max_ptime; - else if (basertppayload->priv->prop_max_ptime != -1) - basertppayload->max_ptime = basertppayload->priv->prop_max_ptime; - else - basertppayload->max_ptime = DEFAULT_MAX_PTIME; -} - -/** - * gst_basertppayload_set_outcaps: - * @payload: a #GstBaseRTPPayload - * @fieldname: the first field name or %NULL - * @...: field values - * - * Configure the output caps with the optional parameters. - * - * Variable arguments should be in the form field name, field type - * (as a GType), value(s). The last variable argument should be NULL. - * - * Returns: %TRUE if the caps could be set. - */ -gboolean -gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload, - const gchar * fieldname, ...) -{ - GstCaps *srccaps, *peercaps; - gboolean res; - - /* fill in the defaults, their properties cannot be negotiated. */ - srccaps = gst_caps_new_simple ("application/x-rtp", - "media", G_TYPE_STRING, payload->media, - "clock-rate", G_TYPE_INT, payload->clock_rate, - "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL); - - GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps); - - if (fieldname) { - va_list varargs; - - /* override with custom properties */ - va_start (varargs, fieldname); - gst_caps_set_simple_valist (srccaps, fieldname, varargs); - va_end (varargs); - - GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps); - } - - payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME; - payload->abidata.ABI.ptime = 0; - - /* the peer caps can override some of the defaults */ - peercaps = gst_pad_peer_get_caps (payload->srcpad); - if (peercaps == NULL) { - /* no peer caps, just add the other properties */ - gst_caps_set_simple (srccaps, - "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload), - "ssrc", G_TYPE_UINT, payload->current_ssrc, - "clock-base", G_TYPE_UINT, payload->ts_base, - "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL); - - GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps); - } else { - GstCaps *temp; - GstStructure *s, *d; - const GValue *value; - gint pt; - guint max_ptime, ptime; - - /* peer provides caps we can use to fixate, intersect. This always returns a - * writable caps. */ - temp = gst_caps_intersect (srccaps, peercaps); - gst_caps_unref (srccaps); - gst_caps_unref (peercaps); - - if (gst_caps_is_empty (temp)) { - gst_caps_unref (temp); - return FALSE; - } - - /* now fixate, start by taking the first caps */ - gst_caps_truncate (temp); - - /* get first structure */ - s = gst_caps_get_structure (temp, 0); - - if (gst_structure_get_uint (s, "maxptime", &max_ptime)) - payload->priv->caps_max_ptime = max_ptime * GST_MSECOND; - - if (gst_structure_get_uint (s, "ptime", &ptime)) - payload->abidata.ABI.ptime = ptime * GST_MSECOND; - - if (gst_structure_get_int (s, "payload", &pt)) { - /* use peer pt */ - GST_BASE_RTP_PAYLOAD_PT (payload) = pt; - GST_LOG_OBJECT (payload, "using peer pt %d", pt); - } else { - if (gst_structure_has_field (s, "payload")) { - /* can only fixate if there is a field */ - gst_structure_fixate_field_nearest_int (s, "payload", - GST_BASE_RTP_PAYLOAD_PT (payload)); - gst_structure_get_int (s, "payload", &pt); - GST_LOG_OBJECT (payload, "using peer pt %d", pt); - } else { - /* no pt field, use the internal pt */ - pt = GST_BASE_RTP_PAYLOAD_PT (payload); - gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL); - GST_LOG_OBJECT (payload, "using internal pt %d", pt); - } - } - - if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "ssrc"); - payload->current_ssrc = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL); - GST_LOG_OBJECT (payload, "using internal ssrc %08x", - payload->current_ssrc); - } - - if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "clock-base"); - payload->ts_base = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL); - GST_LOG_OBJECT (payload, "using internal clock-base %u", - payload->ts_base); - } - if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) { - value = gst_structure_get_value (s, "seqnum-base"); - payload->seqnum_base = g_value_get_uint (value); - GST_LOG_OBJECT (payload, "using peer seqnum-base %u", - payload->seqnum_base); - } else { - /* FIXME, fixate_nearest_uint would be even better */ - gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base, - NULL); - GST_LOG_OBJECT (payload, "using internal seqnum-base %u", - payload->seqnum_base); - } - - /* make the target caps by copying over all the fixed caps, removing the - * unfixed caps. */ - srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL); - d = gst_caps_get_structure (srccaps, 0); - - gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d); - - gst_caps_unref (temp); - - GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); - } - - update_max_ptime (payload); - - res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); - gst_caps_unref (srccaps); - - return res; -} - -/** - * gst_basertppayload_is_filled: - * @payload: a #GstBaseRTPPayload - * @size: the size of the packet - * @duration: the duration of the packet - * - * Check if the packet with @size and @duration would exceed the configured - * maximum size. - * - * Returns: %TRUE if the packet of @size and @duration would exceed the - * configured MTU or max_ptime. - */ -gboolean -gst_basertppayload_is_filled (GstBaseRTPPayload * payload, - guint size, GstClockTime duration) -{ - if (size > payload->mtu) - return TRUE; - - if (payload->max_ptime != -1 && duration >= payload->max_ptime) - return TRUE; - - return FALSE; -} - -typedef struct -{ - GstBaseRTPPayload *payload; - guint32 ssrc; - guint16 seqnum; - guint8 pt; - GstCaps *caps; - GstClockTime timestamp; - guint64 offset; - guint32 rtptime; -} HeaderData; - -static GstBufferListItem -find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) -{ - data->timestamp = GST_BUFFER_TIMESTAMP (*buffer); - data->offset = GST_BUFFER_OFFSET (*buffer); - - /* stop when we find a timestamp. We take whatever offset is associated with - * the timestamp (if any) to do perfect timestamps when we need to. */ - if (data->timestamp != -1) - return GST_BUFFER_LIST_END; - else - return GST_BUFFER_LIST_CONTINUE; -} - -static GstBufferListItem -set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data) -{ - gst_rtp_buffer_set_ssrc (*buffer, data->ssrc); - gst_rtp_buffer_set_payload_type (*buffer, data->pt); - gst_rtp_buffer_set_seq (*buffer, data->seqnum); - gst_rtp_buffer_set_timestamp (*buffer, data->rtptime); - gst_buffer_set_caps (*buffer, data->caps); - /* increment the seqnum for each buffer */ - data->seqnum++; - - return GST_BUFFER_LIST_SKIP_GROUP; -} - -/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer - * before the buffer is pushed. */ -static GstFlowReturn -gst_basertppayload_prepare_push (GstBaseRTPPayload * payload, - gpointer obj, gboolean is_list) -{ - GstBaseRTPPayloadPrivate *priv; - HeaderData data; - - if (payload->clock_rate == 0) - goto no_rate; - - priv = payload->priv; - - /* update first, so that the property is set to the last - * seqnum pushed */ - payload->seqnum = priv->next_seqnum; - - /* fill in the fields we want to set on all headers */ - data.payload = payload; - data.seqnum = payload->seqnum; - data.ssrc = payload->current_ssrc; - data.pt = payload->pt; - data.caps = GST_PAD_CAPS (payload->srcpad); - - /* find the first buffer with a timestamp */ - if (is_list) { - data.timestamp = -1; - data.offset = GST_BUFFER_OFFSET_NONE; - gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), - (GstBufferListFunc) find_timestamp, &data); - } else { - data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj)); - data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj)); - } - - /* convert to RTP time */ - if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE) { - /* if we have an offset, use that for making an RTP timestamp */ - data.rtptime = payload->ts_base + data.offset; - GST_LOG_OBJECT (payload, - "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset); - } else if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) { - gint64 rtime; - - /* no offset, use the gstreamer timestamp */ - rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME, - data.timestamp); - - GST_LOG_OBJECT (payload, - "Using running_time %" GST_TIME_FORMAT " for RTP timestamp", - GST_TIME_ARGS (rtime)); - - rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND); - - /* add running_time in clock-rate units to the base timestamp */ - data.rtptime = payload->ts_base + rtime; - } else { - GST_LOG_OBJECT (payload, - "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp); - /* no timestamp to convert, take previous timestamp */ - data.rtptime = payload->timestamp; - } - - /* set ssrc, payload type, seq number, caps and rtptime */ - if (is_list) { - gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), - (GstBufferListFunc) set_headers, &data); - } else { - GstBuffer *buf = GST_BUFFER_CAST (obj); - set_headers (&buf, 0, 0, &data); - } - - priv->next_seqnum = data.seqnum; - payload->timestamp = data.rtptime; - - GST_LOG_OBJECT (payload, - "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %" - GST_TIME_FORMAT, (is_list) ? -1 : - GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime, - GST_TIME_ARGS (data.timestamp)); - - return GST_FLOW_OK; - - /* ERRORS */ -no_rate: - { - GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL), - ("subclass did not specify clock-rate")); - return GST_FLOW_ERROR; - } -} - -/** - * gst_basertppayload_push_list: - * @payload: a #GstBaseRTPPayload - * @list: a #GstBufferList - * - * Push @list to the peer element of the payloader. The SSRC, payload type, - * seqnum and timestamp of the RTP buffer will be updated first. - * - * This function takes ownership of @list. - * - * Returns: a #GstFlowReturn. - * - * Since: 0.10.24 - */ -GstFlowReturn -gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list) -{ - GstFlowReturn res; - - res = gst_basertppayload_prepare_push (payload, list, TRUE); - - if (G_LIKELY (res == GST_FLOW_OK)) - res = gst_pad_push_list (payload->srcpad, list); - else - gst_buffer_list_unref (list); - - return res; -} - -/** - * gst_basertppayload_push: - * @payload: a #GstBaseRTPPayload - * @buffer: a #GstBuffer - * - * Push @buffer to the peer element of the payloader. The SSRC, payload type, - * seqnum and timestamp of the RTP buffer will be updated first. - * - * This function takes ownership of @buffer. - * - * Returns: a #GstFlowReturn. - */ -GstFlowReturn -gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer) -{ - GstFlowReturn res; - - res = gst_basertppayload_prepare_push (payload, buffer, FALSE); - - if (G_LIKELY (res == GST_FLOW_OK)) - res = gst_pad_push (payload->srcpad, buffer); - else - gst_buffer_unref (buffer); - - return res; -} - -static void -gst_basertppayload_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - gint64 val; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - priv = basertppayload->priv; - - switch (prop_id) { - case PROP_MTU: - basertppayload->mtu = g_value_get_uint (value); - break; - case PROP_PT: - basertppayload->pt = g_value_get_uint (value); - break; - case PROP_SSRC: - val = g_value_get_uint (value); - basertppayload->ssrc = val; - priv->ssrc_random = FALSE; - break; - case PROP_TIMESTAMP_OFFSET: - val = g_value_get_uint (value); - basertppayload->ts_offset = val; - priv->ts_offset_random = FALSE; - break; - case PROP_SEQNUM_OFFSET: - val = g_value_get_int (value); - basertppayload->seqnum_offset = val; - priv->seqnum_offset_random = (val == -1); - GST_DEBUG_OBJECT (basertppayload, "seqnum offset 0x%04x, random %d", - basertppayload->seqnum_offset, priv->seqnum_offset_random); - break; - case PROP_MAX_PTIME: - basertppayload->priv->prop_max_ptime = g_value_get_int64 (value); - update_max_ptime (basertppayload); - break; - case PROP_MIN_PTIME: - basertppayload->min_ptime = g_value_get_int64 (value); - break; - case PROP_PERFECT_RTPTIME: - priv->perfect_rtptime = g_value_get_boolean (value); - break; - case PROP_PTIME_MULTIPLE: - basertppayload->abidata.ABI.ptime_multiple = g_value_get_int64 (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_basertppayload_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - - basertppayload = GST_BASE_RTP_PAYLOAD (object); - priv = basertppayload->priv; - - switch (prop_id) { - case PROP_MTU: - g_value_set_uint (value, basertppayload->mtu); - break; - case PROP_PT: - g_value_set_uint (value, basertppayload->pt); - break; - case PROP_SSRC: - if (priv->ssrc_random) - g_value_set_uint (value, -1); - else - g_value_set_uint (value, basertppayload->ssrc); - break; - case PROP_TIMESTAMP_OFFSET: - if (priv->ts_offset_random) - g_value_set_uint (value, -1); - else - g_value_set_uint (value, (guint32) basertppayload->ts_offset); - break; - case PROP_SEQNUM_OFFSET: - if (priv->seqnum_offset_random) - g_value_set_int (value, -1); - else - g_value_set_int (value, (guint16) basertppayload->seqnum_offset); - break; - case PROP_MAX_PTIME: - g_value_set_int64 (value, basertppayload->max_ptime); - break; - case PROP_MIN_PTIME: - g_value_set_int64 (value, basertppayload->min_ptime); - break; - case PROP_TIMESTAMP: - g_value_set_uint (value, basertppayload->timestamp); - break; - case PROP_SEQNUM: - g_value_set_uint (value, basertppayload->seqnum); - break; - case PROP_PERFECT_RTPTIME: - g_value_set_boolean (value, priv->perfect_rtptime); - break; - case PROP_PTIME_MULTIPLE: - g_value_set_int64 (value, basertppayload->abidata.ABI.ptime_multiple); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_basertppayload_change_state (GstElement * element, - GstStateChange transition) -{ - GstBaseRTPPayload *basertppayload; - GstBaseRTPPayloadPrivate *priv; - GstStateChangeReturn ret; - - basertppayload = GST_BASE_RTP_PAYLOAD (element); - priv = basertppayload->priv; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED); - - if (priv->seqnum_offset_random) - basertppayload->seqnum_base = g_random_int_range (0, G_MAXUINT16); - else - basertppayload->seqnum_base = basertppayload->seqnum_offset; - priv->next_seqnum = basertppayload->seqnum_base; - basertppayload->seqnum = basertppayload->seqnum_base; - - if (priv->ssrc_random) - basertppayload->current_ssrc = g_random_int (); - else - basertppayload->current_ssrc = basertppayload->ssrc; - - if (priv->ts_offset_random) - basertppayload->ts_base = g_random_int (); - else - basertppayload->ts_base = basertppayload->ts_offset; - basertppayload->timestamp = basertppayload->ts_base; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - return ret; -} diff --git a/gst-libs/gst/rtp/gstbasertppayload.c.rej b/gst-libs/gst/rtp/gstbasertppayload.c.rej deleted file mode 100644 index adeb449..0000000 --- a/gst-libs/gst/rtp/gstbasertppayload.c.rej +++ /dev/null @@ -1,16 +0,0 @@ -*************** struct _GstBaseRTPPayloadPrivate -*** 48,53 **** - guint16 next_seqnum; - gboolean perfect_rtptime; - gboolean timestamp_valid; - - gint64 prop_max_ptime; - gint64 caps_max_ptime; ---- 48,54 ---- - guint16 next_seqnum; - gboolean perfect_rtptime; - gboolean timestamp_valid; -+ gboolean notified_first_timestamp; - - gint64 prop_max_ptime; - gint64 caps_max_ptime; diff --git a/gst-libs/gst/rtp/gstrtpbuffer.c.new b/gst-libs/gst/rtp/gstrtpbuffer.c.new deleted file mode 100644 index 87b36d4..0000000 --- a/gst-libs/gst/rtp/gstrtpbuffer.c.new +++ /dev/null @@ -1,1403 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Philippe Khalaf - * Copyright (C) <2006> Wim Taymans - * - * 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. - */ - -/** - * SECTION:gstrtpbuffer - * @short_description: Helper methods for dealing with RTP buffers - * @see_also: #GstBaseRTPPayload, #GstBaseRTPDepayload, gstrtcpbuffer - * - * - * - * The GstRTPBuffer helper functions makes it easy to parse and create regular - * #GstBuffer objects that contain RTP payloads. These buffers are typically of - * 'application/x-rtp' #GstCaps. - * - * - * - * Last reviewed on 2006-07-17 (0.10.10) - */ - -#include "gstrtpbuffer.h" - -#include -#include - -#define GST_RTP_HEADER_LEN 12 - -/* Note: we use bitfields here to make sure the compiler doesn't add padding - * between fields on certain architectures; can't assume aligned access either - */ -typedef struct _GstRTPHeader -{ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - unsigned int csrc_count:4; /* CSRC count */ - unsigned int extension:1; /* header extension flag */ - unsigned int padding:1; /* padding flag */ - unsigned int version:2; /* protocol version */ - unsigned int payload_type:7; /* payload type */ - unsigned int marker:1; /* marker bit */ -#elif G_BYTE_ORDER == G_BIG_ENDIAN - unsigned int version:2; /* protocol version */ - unsigned int padding:1; /* padding flag */ - unsigned int extension:1; /* header extension flag */ - unsigned int csrc_count:4; /* CSRC count */ - unsigned int marker:1; /* marker bit */ - unsigned int payload_type:7; /* payload type */ -#else -#error "G_BYTE_ORDER should be big or little endian." -#endif - unsigned int seq:16; /* sequence number */ - unsigned int timestamp:32; /* timestamp */ - unsigned int ssrc:32; /* synchronization source */ - guint8 csrclist[4]; /* optional CSRC list, 32 bits each */ -} GstRTPHeader; - -#define GST_RTP_HEADER_VERSION(data) (((GstRTPHeader *)(data))->version) -#define GST_RTP_HEADER_PADDING(data) (((GstRTPHeader *)(data))->padding) -#define GST_RTP_HEADER_EXTENSION(data) (((GstRTPHeader *)(data))->extension) -#define GST_RTP_HEADER_CSRC_COUNT(data) (((GstRTPHeader *)(data))->csrc_count) -#define GST_RTP_HEADER_MARKER(data) (((GstRTPHeader *)(data))->marker) -#define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type) -#define GST_RTP_HEADER_SEQ(data) (((GstRTPHeader *)(data))->seq) -#define GST_RTP_HEADER_TIMESTAMP(data) (((GstRTPHeader *)(data))->timestamp) -#define GST_RTP_HEADER_SSRC(data) (((GstRTPHeader *)(data))->ssrc) -#define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i) \ - data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) + \ - ((i) * sizeof(guint32)) -#define GST_RTP_HEADER_CSRC_SIZE(data) (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32)) - -typedef enum -{ - PAYLOAD_TYPE, - SEQ, - TIMESTAMP, - SSRC, - NO_MORE -} rtp_header_data_type; - -static gboolean validate_data (guint8 * data, guint len, guint8 * payload, - guint payload_len); -static guint8 *gst_rtp_buffer_list_get_data (GstBufferList * list); -static void gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list, - gpointer data, rtp_header_data_type type); -static void gst_rtp_buffer_list_set_data (guint8 * rtp_header, gpointer data, - rtp_header_data_type type); - -/** - * gst_rtp_buffer_allocate_data: - * @buffer: a #GstBuffer - * @payload_len: the length of the payload - * @pad_len: the amount of padding - * @csrc_count: the number of CSRC entries - * - * Allocate enough data in @buffer to hold an RTP packet with @csrc_count CSRCs, - * a payload length of @payload_len and padding of @pad_len. - * MALLOCDATA of @buffer will be overwritten and will not be freed. - * All other RTP header fields will be set to 0/FALSE. - */ -void -gst_rtp_buffer_allocate_data (GstBuffer * buffer, guint payload_len, - guint8 pad_len, guint8 csrc_count) -{ - guint len; - guint8 *data; - - g_return_if_fail (csrc_count <= 15); - g_return_if_fail (GST_IS_BUFFER (buffer)); - - len = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32) - + payload_len + pad_len; - - data = g_malloc (len); - GST_BUFFER_MALLOCDATA (buffer) = data; - GST_BUFFER_DATA (buffer) = data; - GST_BUFFER_SIZE (buffer) = len; - - /* fill in defaults */ - GST_RTP_HEADER_VERSION (data) = GST_RTP_VERSION; - GST_RTP_HEADER_PADDING (data) = FALSE; - GST_RTP_HEADER_EXTENSION (data) = FALSE; - GST_RTP_HEADER_CSRC_COUNT (data) = csrc_count; - memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, 0), 0, - csrc_count * sizeof (guint32)); - GST_RTP_HEADER_MARKER (data) = FALSE; - GST_RTP_HEADER_PAYLOAD_TYPE (data) = 0; - GST_RTP_HEADER_SEQ (data) = 0; - GST_RTP_HEADER_TIMESTAMP (data) = 0; - GST_RTP_HEADER_SSRC (data) = 0; -} - -/** - * gst_rtp_buffer_new_take_data: - * @data: data for the new buffer - * @len: the length of data - * - * Create a new buffer and set the data and size of the buffer to @data and @len - * respectively. @data will be freed when the buffer is unreffed, so this - * function transfers ownership of @data to the new buffer. - * - * Returns: A newly allocated buffer with @data and of size @len. - */ -GstBuffer * -gst_rtp_buffer_new_take_data (gpointer data, guint len) -{ - GstBuffer *result; - - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (len > 0, NULL); - - result = gst_buffer_new (); - - GST_BUFFER_MALLOCDATA (result) = data; - GST_BUFFER_DATA (result) = data; - GST_BUFFER_SIZE (result) = len; - - return result; -} - -/** - * gst_rtp_buffer_new_copy_data: - * @data: data for the new buffer - * @len: the length of data - * - * Create a new buffer and set the data to a copy of @len - * bytes of @data and the size to @len. The data will be freed when the buffer - * is freed. - * - * Returns: A newly allocated buffer with a copy of @data and of size @len. - */ -GstBuffer * -gst_rtp_buffer_new_copy_data (gpointer data, guint len) -{ - return gst_rtp_buffer_new_take_data (g_memdup (data, len), len); -} - -/** - * gst_rtp_buffer_new_allocate: - * @payload_len: the length of the payload - * @pad_len: the amount of padding - * @csrc_count: the number of CSRC entries - * - * Allocate a new #Gstbuffer with enough data to hold an RTP packet with @csrc_count CSRCs, - * a payload length of @payload_len and padding of @pad_len. - * All other RTP header fields will be set to 0/FALSE. - * - * Returns: A newly allocated buffer that can hold an RTP packet with given - * parameters. - */ -GstBuffer * -gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len, - guint8 csrc_count) -{ - GstBuffer *result; - - g_return_val_if_fail (csrc_count <= 15, NULL); - - result = gst_buffer_new (); - gst_rtp_buffer_allocate_data (result, payload_len, pad_len, csrc_count); - - return result; -} - -/** - * gst_rtp_buffer_new_allocate_len: - * @packet_len: the total length of the packet - * @pad_len: the amount of padding - * @csrc_count: the number of CSRC entries - * - * Create a new #GstBuffer that can hold an RTP packet that is exactly - * @packet_len long. The length of the payload depends on @pad_len and - * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len(). - * All RTP header fields will be set to 0/FALSE. - * - * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len. - */ -GstBuffer * -gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len, - guint8 csrc_count) -{ - guint len; - - g_return_val_if_fail (csrc_count <= 15, NULL); - - len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count); - - return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count); -} - -/** - * gst_rtp_buffer_calc_header_len: - * @csrc_count: the number of CSRC entries - * - * Calculate the header length of an RTP packet with @csrc_count CSRC entries. - * An RTP packet can have at most 15 CSRC entries. - * - * Returns: The length of an RTP header with @csrc_count CSRC entries. - */ -guint -gst_rtp_buffer_calc_header_len (guint8 csrc_count) -{ - g_return_val_if_fail (csrc_count <= 15, 0); - - return GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32)); -} - -/** - * gst_rtp_buffer_calc_packet_len: - * @payload_len: the length of the payload - * @pad_len: the amount of padding - * @csrc_count: the number of CSRC entries - * - * Calculate the total length of an RTP packet with a payload size of @payload_len, - * a padding of @pad_len and a @csrc_count CSRC entries. - * - * Returns: The total length of an RTP header with given parameters. - */ -guint -gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len, - guint8 csrc_count) -{ - g_return_val_if_fail (csrc_count <= 15, 0); - - return payload_len + GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32)) - + pad_len; -} - -/** - * gst_rtp_buffer_calc_payload_len: - * @packet_len: the length of the total RTP packet - * @pad_len: the amount of padding - * @csrc_count: the number of CSRC entries - * - * Calculate the length of the payload of an RTP packet with size @packet_len, - * a padding of @pad_len and a @csrc_count CSRC entries. - * - * Returns: The length of the payload of an RTP packet with given parameters. - */ -guint -gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len, - guint8 csrc_count) -{ - g_return_val_if_fail (csrc_count <= 15, 0); - - return packet_len - GST_RTP_HEADER_LEN - (csrc_count * sizeof (guint32)) - - pad_len; -} - -/** - * gst_rtp_buffer_validate_data: - * @data: the data to validate - * @len: the length of @data to validate - * - * Check if the @data and @size point to the data of a valid RTP packet. - * This function checks the length, version and padding of the packet data. - * Use this function to validate a packet before using the other functions in - * this module. - * - * Returns: TRUE if the data points to a valid RTP packet. - */ -gboolean -gst_rtp_buffer_validate_data (guint8 * data, guint len) -{ - return validate_data (data, len, NULL, 0); -} - -/** - * gst_rtp_buffer_validate: - * @buffer: the buffer to validate - * - * Check if the data pointed to by @buffer is a valid RTP packet using - * validate_data(). - * Use this function to validate a packet before using the other functions in - * this module. - * - * Returns: TRUE if @buffer is a valid RTP packet. - */ -gboolean -gst_rtp_buffer_validate (GstBuffer * buffer) -{ - guint8 *data; - guint len; - - g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); - - data = GST_BUFFER_DATA (buffer); - len = GST_BUFFER_SIZE (buffer); - - return validate_data (data, len, NULL, 0); -} - -/** - * gst_rtp_buffer_list_validate: - * @list: the buffer list to validate - * - * Check if all RTP packets in the @list are valid using validate_data(). - * Use this function to validate an list before using the other functions in - * this module. - * - * Returns: TRUE if @list consists only of valid RTP packets. - */ -gboolean -gst_rtp_buffer_list_validate (GstBufferList * list) -{ - guint16 prev_seqnum = 0; - GstBufferListIterator *it; - guint i = 0; - - g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE); - - it = gst_buffer_list_iterate (list); - g_return_val_if_fail (it != NULL, FALSE); - - /* iterate through all the RTP packets in the list */ - while (gst_buffer_list_iterator_next_group (it)) { - GstBuffer *rtpbuf; - GstBuffer *paybuf; - guint8 *packet_header; - guint8 *packet_payload; - guint payload_size; - guint packet_size; - - /* each group should consists of 2 buffers: one containing the RTP header - * and the other one the payload */ - if (gst_buffer_list_iterator_n_buffers (it) != 2) - goto invalid_list; - - /* get the RTP header */ - rtpbuf = gst_buffer_list_iterator_next (it); - packet_header = GST_BUFFER_DATA (rtpbuf); - if (packet_header == NULL) - goto invalid_list; - - /* get the payload */ - paybuf = gst_buffer_list_iterator_next (it); - packet_payload = GST_BUFFER_DATA (paybuf); - if (packet_payload == NULL) { - goto invalid_list; - } - payload_size = GST_BUFFER_SIZE (paybuf); - if (payload_size == 0) { - goto invalid_list; - } - - /* the size of the RTP packet within the current group */ - packet_size = GST_BUFFER_SIZE (rtpbuf) + payload_size; - - /* check the sequence number */ - if (G_UNLIKELY (i == 0)) { - prev_seqnum = g_ntohs (GST_RTP_HEADER_SEQ (packet_header)); - i++; - } else { - if (++prev_seqnum != g_ntohs (GST_RTP_HEADER_SEQ (packet_header))) - goto invalid_list; - } - - /* validate packet */ - if (!validate_data (packet_header, packet_size, packet_payload, - payload_size)) { - goto invalid_list; - } - } - - gst_buffer_list_iterator_free (it); - return TRUE; - -invalid_list: - gst_buffer_list_iterator_free (it); - g_return_val_if_reached (FALSE); -} - -/** - * validate_data: - * @data: the data to validate - * @len: the length of @data to validate - * @payload: the payload if @data represents the header only - * @payload_len: the len of the payload - * - * Checks if @data is a valid RTP packet. - * - * Returns: TRUE if @data is a valid RTP packet - */ -static gboolean -validate_data (guint8 * data, guint len, guint8 * payload, guint payload_len) -{ - guint8 padding; - guint8 csrc_count; - guint header_len; - guint8 version; - - g_return_val_if_fail (data != NULL, FALSE); - - header_len = GST_RTP_HEADER_LEN; - if (G_UNLIKELY (len < header_len)) - goto wrong_length; - - /* check version */ - version = (data[0] & 0xc0); - if (G_UNLIKELY (version != (GST_RTP_VERSION << 6))) - goto wrong_version; - - /* calc header length with csrc */ - csrc_count = (data[0] & 0x0f); - header_len += csrc_count * sizeof (guint32); - - /* calc extension length when present. */ - if (data[0] & 0x10) { - guint8 *extpos; - guint16 extlen; - - /* this points to the extenstion bits and header length */ - extpos = &data[header_len]; - - /* skip the header and check that we have enough space */ - header_len += 4; - if (G_UNLIKELY (len < header_len)) - goto wrong_length; - - /* skip id */ - extpos += 2; - /* read length as the number of 32 bits words */ - extlen = GST_READ_UINT16_BE (extpos); - - header_len += extlen * sizeof (guint32); - } - - /* check for padding */ - if (data[0] & 0x20) { - if (payload) - padding = payload[payload_len - 1]; - else - padding = data[len - 1]; - } else { - padding = 0; - } - - /* check if padding and header not bigger than packet length */ - if (G_UNLIKELY (len < padding + header_len)) - goto wrong_padding; - - return TRUE; - - /* ERRORS */ -wrong_length: - { - GST_DEBUG ("len < header_len check failed (%d < %d)", len, header_len); - return FALSE; - } -wrong_version: - { - GST_DEBUG ("version check failed (%d != %d)", version, GST_RTP_VERSION); - return FALSE; - } -wrong_padding: - { - GST_DEBUG ("padding check failed (%d - %d < %d)", len, header_len, padding); - return FALSE; - } -} - -/** - * gst_rtp_buffer_set_packet_len: - * @buffer: the buffer - * @len: the new packet length - * - * Set the total @buffer size to @len. The data in the buffer will be made - * larger if needed. Any padding will be removed from the packet. - */ -void -gst_rtp_buffer_set_packet_len (GstBuffer * buffer, guint len) -{ - guint oldlen; - guint8 *data; - - oldlen = GST_BUFFER_SIZE (buffer); - data = GST_BUFFER_DATA (buffer); - - if (oldlen < len) { - data = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len); - GST_BUFFER_MALLOCDATA (buffer) = data; - GST_BUFFER_DATA (buffer) = data; - } - GST_BUFFER_SIZE (buffer) = len; - - /* remove any padding */ - GST_RTP_HEADER_PADDING (data) = FALSE; -} - -/** - * gst_rtp_buffer_get_packet_len: - * @buffer: the buffer - * - * Return the total length of the packet in @buffer. - * - * Returns: The total length of the packet in @buffer. - */ -guint -gst_rtp_buffer_get_packet_len (GstBuffer * buffer) -{ - return GST_BUFFER_SIZE (buffer); -} - -/** - * gst_rtp_buffer_get_header_len: - * @buffer: the buffer - * - * Return the total length of the header in @buffer. This include the length of - * the fixed header, the CSRC list and the extension header. - * - * Returns: The total length of the header in @buffer. - */ -guint -gst_rtp_buffer_get_header_len (GstBuffer * buffer) -{ - guint len; - guint8 *data; - - data = GST_BUFFER_DATA (buffer); - - len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data); - if (GST_RTP_HEADER_EXTENSION (data)) - len += GST_READ_UINT16_BE (data + len + 2) * 4 + 4; - - return len; -} - -/** - * gst_rtp_buffer_get_version: - * @buffer: the buffer - * - * Get the version number of the RTP packet in @buffer. - * - * Returns: The version of @buffer. - */ -guint8 -gst_rtp_buffer_get_version (GstBuffer * buffer) -{ - return GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_set_version: - * @buffer: the buffer - * @version: the new version - * - * Set the version of the RTP packet in @buffer to @version. - */ -void -gst_rtp_buffer_set_version (GstBuffer * buffer, guint8 version) -{ - g_return_if_fail (version < 0x04); - - GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)) = version; -} - -/** - * gst_rtp_buffer_get_padding: - * @buffer: the buffer - * - * Check if the padding bit is set on the RTP packet in @buffer. - * - * Returns: TRUE if @buffer has the padding bit set. - */ -gboolean -gst_rtp_buffer_get_padding (GstBuffer * buffer) -{ - return GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_set_padding: - * @buffer: the buffer - * @padding: the new padding - * - * Set the padding bit on the RTP packet in @buffer to @padding. - */ -void -gst_rtp_buffer_set_padding (GstBuffer * buffer, gboolean padding) -{ - GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)) = padding; -} - -/** - * gst_rtp_buffer_pad_to: - * @buffer: the buffer - * @len: the new amount of padding - * - * Set the amount of padding in the RTP packet in @buffer to - * @len. If @len is 0, the padding is removed. - * - * NOTE: This function does not work correctly. - */ -void -gst_rtp_buffer_pad_to (GstBuffer * buffer, guint len) -{ - guint8 *data; - - data = GST_BUFFER_DATA (buffer); - - if (len > 0) - GST_RTP_HEADER_PADDING (data) = TRUE; - else - GST_RTP_HEADER_PADDING (data) = FALSE; - - /* FIXME, set the padding byte at the end of the payload data */ -} - -/** - * gst_rtp_buffer_get_extension: - * @buffer: the buffer - * - * Check if the extension bit is set on the RTP packet in @buffer. - * - * Returns: TRUE if @buffer has the extension bit set. - */ -gboolean -gst_rtp_buffer_get_extension (GstBuffer * buffer) -{ - return GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_set_extension: - * @buffer: the buffer - * @extension: the new extension - * - * Set the extension bit on the RTP packet in @buffer to @extension. - */ -void -gst_rtp_buffer_set_extension (GstBuffer * buffer, gboolean extension) -{ - GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)) = extension; -} - -/** - * gst_rtp_buffer_get_extension_data: - * @buffer: the buffer - * @bits: location for result bits - * @data: location for data - * @wordlen: location for length of @data in 32 bits words - * - * Get the extension data. @bits will contain the extension 16 bits of custom - * data. @data will point to the data in the extension and @wordlen will contain - * the length of @data in 32 bits words. - * - * If @buffer did not contain an extension, this function will return %FALSE - * with @bits, @data and @wordlen unchanged. - * - * Returns: TRUE if @buffer had the extension bit set. - * - * Since: 0.10.15 - */ -gboolean -gst_rtp_buffer_get_extension_data (GstBuffer * buffer, guint16 * bits, - gpointer * data, guint * wordlen) -{ - guint len; - guint8 *pdata; - - pdata = GST_BUFFER_DATA (buffer); - - if (!GST_RTP_HEADER_EXTENSION (pdata)) - return FALSE; - - /* move to the extension */ - len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (pdata); - pdata += len; - - if (bits) - *bits = GST_READ_UINT16_BE (pdata); - if (wordlen) - *wordlen = GST_READ_UINT16_BE (pdata + 2); - if (data) - *data = pdata + 4; - - return TRUE; -} - -/** - * gst_rtp_buffer_set_extension_data: - * @buffer: the buffer - * @bits: the bits specific for the extension - * @length: the length that counts the number of 32-bit words in - * the extension, excluding the extension header ( therefore zero is a valid length) - * - * Set the extension bit of the rtp buffer and fill in the @bits and @length of the - * extension header. It will refuse to set the extension data if the buffer is not - * large enough. - * - * Returns: True if done. - * - * Since : 0.10.18 - */ -gboolean -gst_rtp_buffer_set_extension_data (GstBuffer * buffer, guint16 bits, - guint16 length) -{ - guint32 min_size = 0; - guint8 *data; - - data = GST_BUFFER_DATA (buffer); - - /* check if the buffer is big enough to hold the extension */ - min_size = - GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data) + 4 + - length * sizeof (guint32); - if (G_UNLIKELY (min_size > GST_BUFFER_SIZE (buffer))) - goto too_small; - - /* now we can set the extension bit */ - gst_rtp_buffer_set_extension (buffer, TRUE); - - data += GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data); - GST_WRITE_UINT16_BE (data, bits); - GST_WRITE_UINT16_BE (data + 2, length); - - return TRUE; - - /* ERRORS */ -too_small: - { - g_warning - ("rtp buffer too small: need more than %d bytes but only have %d bytes", - min_size, GST_BUFFER_SIZE (buffer)); - return FALSE; - } -} - -/** - * gst_rtp_buffer_get_ssrc: - * @buffer: the buffer - * - * Get the SSRC of the RTP packet in @buffer. - * - * Returns: the SSRC of @buffer in host order. - */ -guint32 -gst_rtp_buffer_get_ssrc (GstBuffer * buffer) -{ - return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer))); -} - -/** - * gst_rtp_buffer_list_get_ssrc: - * @list: the list - * - * Get the SSRC of the first RTP packet in @list. - * All RTP packets within @list have the same SSRC. - * - * Returns: the SSRC of @list in host order. - */ -guint32 -gst_rtp_buffer_list_get_ssrc (GstBufferList * list) -{ - guint8 *data; - data = gst_rtp_buffer_list_get_data (list); - g_return_val_if_fail (data != NULL, 0); - return g_ntohl (GST_RTP_HEADER_SSRC (data)); -} - -/** - * gst_rtp_buffer_set_ssrc: - * @buffer: the buffer - * @ssrc: the new SSRC - * - * Set the SSRC on the RTP packet in @buffer to @ssrc. - */ -void -gst_rtp_buffer_set_ssrc (GstBuffer * buffer, guint32 ssrc) -{ - GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)) = g_htonl (ssrc); -} - -/** - * gst_rtp_buffer_list_set_ssrc: - * @list: the buffer list - * @ssrc: the new SSRC - * - * Set the SSRC on each RTP packet in @list to @ssrc. - */ -void -gst_rtp_buffer_list_set_ssrc (GstBufferList * list, guint32 ssrc) -{ - gst_rtp_buffer_list_set_rtp_headers (list, &ssrc, SSRC); -} - -/** - * gst_rtp_buffer_get_csrc_count: - * @buffer: the buffer - * - * Get the CSRC count of the RTP packet in @buffer. - * - * Returns: the CSRC count of @buffer. - */ -guint8 -gst_rtp_buffer_get_csrc_count (GstBuffer * buffer) -{ - return GST_RTP_HEADER_CSRC_COUNT (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_get_csrc: - * @buffer: the buffer - * @idx: the index of the CSRC to get - * - * Get the CSRC at index @idx in @buffer. - * - * Returns: the CSRC at index @idx in host order. - */ -guint32 -gst_rtp_buffer_get_csrc (GstBuffer * buffer, guint8 idx) -{ - guint8 *data; - - data = GST_BUFFER_DATA (buffer); - - g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0); - - return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx)); -} - -/** - * gst_rtp_buffer_set_csrc: - * @buffer: the buffer - * @idx: the CSRC index to set - * @csrc: the CSRC in host order to set at @idx - * - * Modify the CSRC at index @idx in @buffer to @csrc. - */ -void -gst_rtp_buffer_set_csrc (GstBuffer * buffer, guint8 idx, guint32 csrc) -{ - guint8 *data; - - data = GST_BUFFER_DATA (buffer); - - g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data)); - - GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc); -} - -/** - * gst_rtp_buffer_get_marker: - * @buffer: the buffer - * - * Check if the marker bit is set on the RTP packet in @buffer. - * - * Returns: TRUE if @buffer has the marker bit set. - */ -gboolean -gst_rtp_buffer_get_marker (GstBuffer * buffer) -{ - return GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_set_marker: - * @buffer: the buffer - * @marker: the new marker - * - * Set the marker bit on the RTP packet in @buffer to @marker. - */ -void -gst_rtp_buffer_set_marker (GstBuffer * buffer, gboolean marker) -{ - GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)) = marker; -} - -/** - * gst_rtp_buffer_get_payload_type: - * @buffer: the buffer - * - * Get the payload type of the RTP packet in @buffer. - * - * Returns: The payload type. - */ -guint8 -gst_rtp_buffer_get_payload_type (GstBuffer * buffer) -{ - return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)); -} - -/** - * gst_rtp_buffer_list_get_payload_type: - * @list: the list - * - * Get the payload type of the first RTP packet in @list. - * All packets in @list should have the same payload type. - * - * Returns: The payload type. - */ -guint8 -gst_rtp_buffer_list_get_payload_type (GstBufferList * list) -{ - guint8 *data; - data = gst_rtp_buffer_list_get_data (list); - g_return_val_if_fail (data != NULL, 0); - return GST_RTP_HEADER_PAYLOAD_TYPE (data); -} - -/** - * gst_rtp_buffer_set_payload_type: - * @buffer: the buffer - * @payload_type: the new type - * - * Set the payload type of the RTP packet in @buffer to @payload_type. - */ -void -gst_rtp_buffer_set_payload_type (GstBuffer * buffer, guint8 payload_type) -{ - g_return_if_fail (payload_type < 0x80); - - GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)) = payload_type; -} - -/** - * gst_rtp_buffer_list_set_payload_type: - * @list: the buffer list - * @payload_type: the new type - * - * Set the payload type of each RTP packet in @list to @payload_type. - */ -void -gst_rtp_buffer_list_set_payload_type (GstBufferList * list, guint8 payload_type) -{ - g_return_if_fail (payload_type < 0x80); - - gst_rtp_buffer_list_set_rtp_headers (list, &payload_type, PAYLOAD_TYPE); -} - -/** - * gst_rtp_buffer_get_seq: - * @buffer: the buffer - * - * Get the sequence number of the RTP packet in @buffer. - * - * Returns: The sequence number in host order. - */ -guint16 -gst_rtp_buffer_get_seq (GstBuffer * buffer) -{ - return g_ntohs (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer))); -} - -/** - * gst_rtp_buffer_set_seq: - * @buffer: the buffer - * @seq: the new sequence number - * - * Set the sequence number of the RTP packet in @buffer to @seq. - */ -void -gst_rtp_buffer_set_seq (GstBuffer * buffer, guint16 seq) -{ - GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)) = g_htons (seq); -} - -/** - * gst_rtp_buffer_list_set_seq: - * @list: the buffer list - * @seq: the new sequence number - * - * Set the sequence number of each RTP packet in @list to @seq. - * - * Returns: The seq number of the last packet in the list + 1. - */ -guint16 -gst_rtp_buffer_list_set_seq (GstBufferList * list, guint16 seq) -{ - gst_rtp_buffer_list_set_rtp_headers (list, &seq, SEQ); - return seq; -} - -/** - * gst_rtp_buffer_get_timestamp: - * @buffer: the buffer - * - * Get the timestamp of the RTP packet in @buffer. - * - * Returns: The timestamp in host order. - */ -guint32 -gst_rtp_buffer_get_timestamp (GstBuffer * buffer) -{ - return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer))); -} - -/** - * gst_rtp_buffer_list_get_timestamp: - * @list: the list - * - * Get the timestamp of the first RTP packet in @list. - * All packets within @list have the same timestamp. - * - * Returns: The timestamp in host order. - */ -guint32 -gst_rtp_buffer_list_get_timestamp (GstBufferList * list) -{ - guint8 *data; - data = gst_rtp_buffer_list_get_data (list); - g_return_val_if_fail (data != NULL, 0); - return g_ntohl (GST_RTP_HEADER_TIMESTAMP (data)); -} - -/** - * gst_rtp_buffer_set_timestamp: - * @buffer: the buffer - * @timestamp: the new timestamp - * - * Set the timestamp of the RTP packet in @buffer to @timestamp. - */ -void -gst_rtp_buffer_set_timestamp (GstBuffer * buffer, guint32 timestamp) -{ - GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)) = g_htonl (timestamp); -} - -/** - * gst_rtp_buffer_list_set_timestamp: - * @list: the buffer list - * @timestamp: the new timestamp - * - * Set the timestamp of each RTP packet in @list to @timestamp. - */ -void -gst_rtp_buffer_list_set_timestamp (GstBufferList * list, guint32 timestamp) -{ - gst_rtp_buffer_list_set_rtp_headers (list, ×tamp, TIMESTAMP); -} - -/** - * gst_rtp_buffer_get_payload_subbuffer: - * @buffer: the buffer - * @offset: the offset in the payload - * @len: the length in the payload - * - * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes - * are skipped in the payload and the subbuffer will be of size @len. - * If @len is -1 the total payload starting from @offset if subbuffered. - * - * Returns: A new buffer with the specified data of the payload. - * - * Since: 0.10.10 - */ -GstBuffer * -gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset, - guint len) -{ - guint poffset, plen; - - plen = gst_rtp_buffer_get_payload_len (buffer); - /* we can't go past the length */ - if (G_UNLIKELY (offset >= plen)) - goto wrong_offset; - - /* apply offset */ - poffset = gst_rtp_buffer_get_header_len (buffer) + offset; - plen -= offset; - - /* see if we need to shrink the buffer based on @len */ - if (len != -1 && len < plen) - plen = len; - - return gst_buffer_create_sub (buffer, poffset, plen); - - /* ERRORS */ -wrong_offset: - { - g_warning ("offset=%u should be less then plen=%u", offset, plen); - return NULL; - } -} - -/** - * gst_rtp_buffer_get_payload_buffer: - * @buffer: the buffer - * - * Create a buffer of the payload of the RTP packet in @buffer. This function - * will internally create a subbuffer of @buffer so that a memcpy can be - * avoided. - * - * Returns: A new buffer with the data of the payload. - */ -GstBuffer * -gst_rtp_buffer_get_payload_buffer (GstBuffer * buffer) -{ - return gst_rtp_buffer_get_payload_subbuffer (buffer, 0, -1); -} - -/** - * gst_rtp_buffer_get_payload_len: - * @buffer: the buffer - * - * Get the length of the payload of the RTP packet in @buffer. - * - * Returns: The length of the payload in @buffer. - */ -guint -gst_rtp_buffer_get_payload_len (GstBuffer * buffer) -{ - guint len, size; - guint8 *data; - - size = GST_BUFFER_SIZE (buffer); - data = GST_BUFFER_DATA (buffer); - - len = size - gst_rtp_buffer_get_header_len (buffer); - - if (GST_RTP_HEADER_PADDING (data)) - len -= data[size - 1]; - - return len; -} - -/** - * gst_rtp_buffer_list_get_payload_len: - * @buffer: the buffer - * - * Get the length of the payload of the RTP packet in @list. - * - * Returns: The length of the payload in @list. - */ -guint -gst_rtp_buffer_list_get_payload_len (GstBufferList * list) -{ - guint len = 0; - GstBufferListIterator *it; - it = gst_buffer_list_iterate (list); - - while (gst_buffer_list_iterator_next_group (it)) { - guint i; - GstBuffer *buf; - - i = 0; - while ((buf = gst_buffer_list_iterator_next (it))) { - /* skip the RTP header */ - if (!i++) - continue; - /* take the size of the current buffer */ - len += GST_BUFFER_SIZE (buf); - } - } - - gst_buffer_list_iterator_free (it); - - return len; -} - -/** - * gst_rtp_buffer_get_payload: - * @buffer: the buffer - * - * Get a pointer to the payload data in @buffer. This pointer is valid as long - * as a reference to @buffer is held. - * - * Returns: A pointer to the payload data in @buffer. - */ -gpointer -gst_rtp_buffer_get_payload (GstBuffer * buffer) -{ - return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer); -} - -/** - * gst_rtp_buffer_default_clock_rate: - * @payload_type: the static payload type - * - * Get the default clock-rate for the static payload type @payload_type. - * - * Returns: the default clock rate or -1 if the payload type is not static or - * the clock-rate is undefined. - * - * Since: 0.10.13 - */ -guint32 -gst_rtp_buffer_default_clock_rate (guint8 payload_type) -{ - const GstRTPPayloadInfo *info; - guint32 res; - - info = gst_rtp_payload_info_for_pt (payload_type); - if (!info) - return -1; - - res = info->clock_rate; - /* 0 means unknown so we have to return -1 from this function */ - if (res == 0) - res = -1; - - return res; -} - -/** - * gst_rtp_buffer_compare_seqnum: - * @seqnum1: a sequence number - * @seqnum2: a sequence number - * - * Compare two sequence numbers, taking care of wraparounds. This function - * returns the difference between @seqnum1 and @seqnum2. - * - * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they - * are equal or a positive value if @seqnum1 is smaller than @segnum2. - * - * Since: 0.10.15 - */ -gint -gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2) -{ - return (gint16) (seqnum2 - seqnum1); -} - -/** - * gst_rtp_buffer_ext_timestamp: - * @exttimestamp: a previous extended timestamp - * @timestamp: a new timestamp - * - * Update the @exttimestamp field with @timestamp. For the first call of the - * method, @exttimestamp should point to a location with a value of -1. - * - * This function makes sure that the returned value is a constantly increasing - * value even in the case where there is a timestamp wraparound. - * - * Returns: The extended timestamp of @timestamp. - * - * Since: 0.10.15 - */ -guint64 -gst_rtp_buffer_ext_timestamp (guint64 * exttimestamp, guint32 timestamp) -{ - guint64 result, diff, ext; - - g_return_val_if_fail (exttimestamp != NULL, -1); - - ext = *exttimestamp; - - if (ext == -1) { - result = timestamp; - } else { - /* pick wraparound counter from previous timestamp and add to new timestamp */ - result = timestamp + (ext & ~(G_GINT64_CONSTANT (0xffffffff))); - - /* check for timestamp wraparound */ - if (result < ext) - diff = ext - result; - else - diff = result - ext; - - if (diff > G_MAXINT32) { - /* timestamp went backwards more than allowed, we wrap around and get - * updated extended timestamp. */ - result += (G_GINT64_CONSTANT (1) << 32); - } - } - *exttimestamp = result; - - return result; -} - -/** - * gst_rtp_buffer_list_get_data: - * @list: a buffer list - * - * Returns ponter to the RTP header of the first packet within the list - * - * Returns: pointer to the first RTP header - */ -static guint8 * -gst_rtp_buffer_list_get_data (GstBufferList * list) -{ - GstBufferListIterator *it; - GstBuffer *rtpbuf; - - it = gst_buffer_list_iterate (list); - if (!gst_buffer_list_iterator_next_group (it)) - goto invalid_list; - rtpbuf = gst_buffer_list_iterator_next (it); - if (!rtpbuf) - goto invalid_list; - - gst_buffer_list_iterator_free (it); - return GST_BUFFER_DATA (rtpbuf); - -invalid_list: - gst_buffer_list_iterator_free (it); - g_return_val_if_reached (FALSE); -} - -/** - * gst_rtp_buffer_list_set_rtp_headers: - * @list: a buffer list - * @data: data to be set - * @type: which field in the header to be set - * - * Sets the field specified by @type to @data. - * This function updates all RTP headers within @list. - */ -static void -gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list, - gpointer data, rtp_header_data_type type) -{ - GstBufferListIterator *it; - it = gst_buffer_list_iterate (list); - - while (gst_buffer_list_iterator_next_group (it)) { - GstBuffer *rtpbuf; - guint8 *rtp_header; - rtpbuf = gst_buffer_list_iterator_next (it); - rtp_header = GST_BUFFER_DATA (rtpbuf); - gst_rtp_buffer_list_set_data (rtp_header, data, type); - } - - gst_buffer_list_iterator_free (it); -} - -/** - * gst_rtp_buffer_list_set_data: - * @rtp_header: rtp header to be updated - * @data: data to be set - * @type: which field in the header to be set - * - * Sets the field specified by @type to @data. - * When setting SEQ number, this function will also increase - * @data by one. - */ -static void -gst_rtp_buffer_list_set_data (guint8 * rtp_header, - gpointer data, rtp_header_data_type type) -{ - switch (type) { - case PAYLOAD_TYPE: - GST_RTP_HEADER_PAYLOAD_TYPE (rtp_header) = *(guint8 *) data; - break; - case SEQ: - GST_RTP_HEADER_SEQ (rtp_header) = g_htons (*(guint16 *) data); - (*(guint16 *) data)++; - break; - case SSRC: - GST_RTP_HEADER_SSRC (rtp_header) = g_htonl (*(guint32 *) data); - break; - case TIMESTAMP: - GST_RTP_HEADER_TIMESTAMP (rtp_header) = g_htonl (*(guint32 *) data); - break; - default: - g_warning ("Unknown data type"); - break; - } -} diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c.orig b/gst-libs/gst/rtsp/gstrtspconnection.c.orig deleted file mode 100644 index 088a67e..0000000 --- a/gst-libs/gst/rtsp/gstrtspconnection.c.orig +++ /dev/null @@ -1,3519 +0,0 @@ -/* GStreamer - * Copyright (C) <2005-2009> Wim Taymans - * - * 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. - */ -/* - * Unless otherwise indicated, Source Code is licensed under MIT license. - * See further explanation attached in License Statement (distributed in the file - * LICENSE). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * SECTION:gstrtspconnection - * @short_description: manage RTSP connections - * @see_also: gstrtspurl - * - * - * - * This object manages the RTSP connection to the server. It provides function - * to receive and send bytes and messages. - * - * - * - * Last reviewed on 2007-07-24 (0.10.14) - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -/* we include this here to get the G_OS_* defines */ -#include -#include - -#ifdef G_OS_WIN32 -/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later. - * minwg32 headers check WINVER before allowing the use of these */ -#ifndef WINVER -#define WINVER 0x0501 -#endif -#include -#include -#define EINPROGRESS WSAEINPROGRESS -#else -#include -#include -#include -#include -#include -#endif - -#ifdef HAVE_FIONREAD_IN_SYS_FILIO -#include -#endif - -#include "gstrtspconnection.h" -#include "gstrtspbase64.h" - -union gst_sockaddr -{ - struct sockaddr sa; - struct sockaddr_in sa_in; - struct sockaddr_in6 sa_in6; - struct sockaddr_storage sa_stor; -}; - -typedef struct -{ - gint state; - guint save; - guchar out[3]; /* the size must be evenly divisible by 3 */ - guint cout; - guint coutl; -} DecodeCtx; - -#ifdef G_OS_WIN32 -#define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0) -#define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0) -#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, (const char *)val, len) -#define CLOSE_SOCKET(sock) closesocket (sock) -#define ERRNO_IS_EAGAIN (WSAGetLastError () == WSAEWOULDBLOCK) -#define ERRNO_IS_EINTR (WSAGetLastError () == WSAEINTR) -/* According to Microsoft's connect() documentation this one returns - * WSAEWOULDBLOCK and not WSAEINPROGRESS. */ -#define ERRNO_IS_EINPROGRESS (WSAGetLastError () == WSAEWOULDBLOCK) -#else -#define READ_SOCKET(fd, buf, len) read (fd, buf, len) -#define WRITE_SOCKET(fd, buf, len) write (fd, buf, len) -#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, val, len) -#define CLOSE_SOCKET(sock) close (sock) -#define ERRNO_IS_EAGAIN (errno == EAGAIN) -#define ERRNO_IS_EINTR (errno == EINTR) -#define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS) -#endif - -#define ADD_POLLFD(fdset, pfd, fd) \ -G_STMT_START { \ - (pfd)->fd = fd; \ - gst_poll_add_fd (fdset, pfd); \ -} G_STMT_END - -#define REMOVE_POLLFD(fdset, pfd) \ -G_STMT_START { \ - if ((pfd)->fd != -1) { \ - GST_DEBUG ("remove fd %d", (pfd)->fd); \ - gst_poll_remove_fd (fdset, pfd); \ - CLOSE_SOCKET ((pfd)->fd); \ - (pfd)->fd = -1; \ - } \ -} G_STMT_END - -typedef enum -{ - TUNNEL_STATE_NONE, - TUNNEL_STATE_GET, - TUNNEL_STATE_POST, - TUNNEL_STATE_COMPLETE -} GstRTSPTunnelState; - -#define TUNNELID_LEN 24 - -struct _GstRTSPConnection -{ - /*< private > */ - /* URL for the connection */ - GstRTSPUrl *url; - - /* connection state */ - GstPollFD fd0; - GstPollFD fd1; - - GstPollFD *readfd; - GstPollFD *writefd; - - gboolean manual_http; - - gchar tunnelid[TUNNELID_LEN]; - gboolean tunneled; - GstRTSPTunnelState tstate; - - GstPoll *fdset; - gchar *ip; - - gint read_ahead; - - gchar *initial_buffer; - gsize initial_buffer_offset; - - /* Session state */ - gint cseq; /* sequence number */ - gchar session_id[512]; /* session id */ - gint timeout; /* session timeout in seconds */ - GTimer *timer; /* timeout timer */ - - /* Authentication */ - GstRTSPAuthMethod auth_method; - gchar *username; - gchar *passwd; - GHashTable *auth_params; - - DecodeCtx ctx; - DecodeCtx *ctxp; - - gchar *proxy_host; - guint proxy_port; -}; - -enum -{ - STATE_START = 0, - STATE_DATA_HEADER, - STATE_DATA_BODY, - STATE_READ_LINES, - STATE_END, - STATE_LAST -}; - -enum -{ - READ_AHEAD_EOH = -1, /* end of headers */ - READ_AHEAD_CRLF = -2, - READ_AHEAD_CRLFCR = -3 -}; - -/* a structure for constructing RTSPMessages */ -typedef struct -{ - gint state; - GstRTSPResult status; - guint8 buffer[4096]; - guint offset; - - guint line; - guint8 *body_data; - glong body_len; -} GstRTSPBuilder; - -static void -build_reset (GstRTSPBuilder * builder) -{ - g_free (builder->body_data); - memset (builder, 0, sizeof (GstRTSPBuilder)); -} - -/** - * gst_rtsp_connection_create: - * @url: a #GstRTSPUrl - * @conn: storage for a #GstRTSPConnection - * - * Create a newly allocated #GstRTSPConnection from @url and store it in @conn. - * The connection will not yet attempt to connect to @url, use - * gst_rtsp_connection_connect(). - * - * A copy of @url will be made. - * - * Returns: #GST_RTSP_OK when @conn contains a valid connection. - */ -GstRTSPResult -gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn) -{ - GstRTSPConnection *newconn; -#ifdef G_OS_WIN32 - WSADATA w; - int error; -#endif - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - -#ifdef G_OS_WIN32 - error = WSAStartup (0x0202, &w); - - if (error) - goto startup_error; - - if (w.wVersion != 0x0202) - goto version_error; -#endif - - newconn = g_new0 (GstRTSPConnection, 1); - - if ((newconn->fdset = gst_poll_new (TRUE)) == NULL) - goto no_fdset; - - newconn->url = gst_rtsp_url_copy (url); - newconn->fd0.fd = -1; - newconn->fd1.fd = -1; - newconn->timer = g_timer_new (); - newconn->timeout = 60; - newconn->cseq = 1; - - newconn->auth_method = GST_RTSP_AUTH_NONE; - newconn->username = NULL; - newconn->passwd = NULL; - newconn->auth_params = NULL; - - *conn = newconn; - - return GST_RTSP_OK; - - /* ERRORS */ -#ifdef G_OS_WIN32 -startup_error: - { - g_warning ("Error %d on WSAStartup", error); - return GST_RTSP_EWSASTART; - } -version_error: - { - g_warning ("Windows sockets are not version 0x202 (current 0x%x)", - w.wVersion); - WSACleanup (); - return GST_RTSP_EWSAVERSION; - } -#endif -no_fdset: - { - g_free (newconn); -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - return GST_RTSP_ESYS; - } -} - -/** - * gst_rtsp_connection_create_from_fd: - * @fd: a file descriptor - * @ip: the IP address of the other end - * @port: the port used by the other end - * @initial_buffer: data already read from @fd - * @conn: storage for a #GstRTSPConnection - * - * Create a new #GstRTSPConnection for handling communication on the existing - * file descriptor @fd. The @initial_buffer contains any data already read from - * @fd which should be used before starting to read new data. - * - * Returns: #GST_RTSP_OK when @conn contains a valid connection. - * - * Since: 0.10.25 - */ -GstRTSPResult -gst_rtsp_connection_create_from_fd (gint fd, const gchar * ip, guint16 port, - const gchar * initial_buffer, GstRTSPConnection ** conn) -{ - GstRTSPConnection *newconn = NULL; - GstRTSPUrl *url; -#ifdef G_OS_WIN32 - gulong flags = 1; -#endif - GstRTSPResult res; - - g_return_val_if_fail (fd >= 0, GST_RTSP_EINVAL); - g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - /* set to non-blocking mode so that we can cancel the communication */ -#ifndef G_OS_WIN32 - fcntl (fd, F_SETFL, O_NONBLOCK); -#else - ioctlsocket (fd, FIONBIO, &flags); -#endif /* G_OS_WIN32 */ - - /* create a url for the client address */ - url = g_new0 (GstRTSPUrl, 1); - url->host = g_strdup (ip); - url->port = port; - - /* now create the connection object */ - GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed); - gst_rtsp_url_free (url); - - ADD_POLLFD (newconn->fdset, &newconn->fd0, fd); - - /* both read and write initially */ - newconn->readfd = &newconn->fd0; - newconn->writefd = &newconn->fd0; - - newconn->ip = g_strdup (ip); - - newconn->initial_buffer = g_strdup (initial_buffer); - - *conn = newconn; - - return GST_RTSP_OK; - - /* ERRORS */ -newconn_failed: - { - gst_rtsp_url_free (url); - return res; - } -} - -/** - * gst_rtsp_connection_accept: - * @sock: a socket - * @conn: storage for a #GstRTSPConnection - * - * Accept a new connection on @sock and create a new #GstRTSPConnection for - * handling communication on new socket. - * - * Returns: #GST_RTSP_OK when @conn contains a valid connection. - * - * Since: 0.10.23 - */ -GstRTSPResult -gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn) -{ - int fd; - union gst_sockaddr sa; - socklen_t slen = sizeof (sa); - gchar ip[INET6_ADDRSTRLEN]; - guint16 port; - - g_return_val_if_fail (sock >= 0, GST_RTSP_EINVAL); - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - memset (&sa, 0, slen); - -#ifndef G_OS_WIN32 - fd = accept (sock, &sa.sa, &slen); -#else - fd = accept (sock, &sa.sa, (gint *) & slen); -#endif /* G_OS_WIN32 */ - if (fd == -1) - goto accept_failed; - - if (getnameinfo (&sa.sa, slen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0) - goto getnameinfo_failed; - - if (sa.sa.sa_family == AF_INET) - port = sa.sa_in.sin_port; - else if (sa.sa.sa_family == AF_INET6) - port = sa.sa_in6.sin6_port; - else - goto wrong_family; - - return gst_rtsp_connection_create_from_fd (fd, ip, port, NULL, conn); - - /* ERRORS */ -accept_failed: - { - return GST_RTSP_ESYS; - } -getnameinfo_failed: -wrong_family: - { - CLOSE_SOCKET (fd); - return GST_RTSP_ERROR; - } -} - -static gchar * -do_resolve (const gchar * host) -{ - static gchar ip[INET6_ADDRSTRLEN]; - struct addrinfo *aires; - struct addrinfo *ai; - gint aierr; - - aierr = getaddrinfo (host, NULL, NULL, &aires); - if (aierr != 0) - goto no_addrinfo; - - for (ai = aires; ai; ai = ai->ai_next) { - if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { - break; - } - } - if (ai == NULL) - goto no_family; - - aierr = getnameinfo (ai->ai_addr, ai->ai_addrlen, ip, sizeof (ip), NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV); - if (aierr != 0) - goto no_address; - - freeaddrinfo (aires); - - return g_strdup (ip); - - /* ERRORS */ -no_addrinfo: - { - GST_ERROR ("no addrinfo found for %s: %s", host, gai_strerror (aierr)); - return NULL; - } -no_family: - { - GST_ERROR ("no family found for %s", host); - freeaddrinfo (aires); - return NULL; - } -no_address: - { - GST_ERROR ("no address found for %s: %s", host, gai_strerror (aierr)); - freeaddrinfo (aires); - return NULL; - } -} - -static GstRTSPResult -do_connect (const gchar * ip, guint16 port, GstPollFD * fdout, - GstPoll * fdset, GTimeVal * timeout) -{ - gint fd; - struct addrinfo hints; - struct addrinfo *aires; - struct addrinfo *ai; - gint aierr; - gchar service[NI_MAXSERV]; - gint ret; -#ifdef G_OS_WIN32 - unsigned long flags = 1; -#endif /* G_OS_WIN32 */ - GstClockTime to; - gint retval; - - memset (&hints, 0, sizeof hints); - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - g_snprintf (service, sizeof (service) - 1, "%hu", port); - service[sizeof (service) - 1] = '\0'; - - aierr = getaddrinfo (ip, service, &hints, &aires); - if (aierr != 0) - goto no_addrinfo; - - for (ai = aires; ai; ai = ai->ai_next) { - if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { - break; - } - } - if (ai == NULL) - goto no_family; - - fd = socket (ai->ai_family, SOCK_STREAM, 0); - if (fd == -1) - goto no_socket; - - /* set to non-blocking mode so that we can cancel the connect */ -#ifndef G_OS_WIN32 - fcntl (fd, F_SETFL, O_NONBLOCK); -#else - ioctlsocket (fd, FIONBIO, &flags); -#endif /* G_OS_WIN32 */ - - /* add the socket to our fdset */ - ADD_POLLFD (fdset, fdout, fd); - - /* we are going to connect ASYNC now */ - ret = connect (fd, ai->ai_addr, ai->ai_addrlen); - if (ret == 0) - goto done; - if (!ERRNO_IS_EINPROGRESS) - goto sys_error; - - /* wait for connect to complete up to the specified timeout or until we got - * interrupted. */ - gst_poll_fd_ctl_write (fdset, fdout, TRUE); - - to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE; - - do { - retval = gst_poll_wait (fdset, to); - } while (retval == -1 && (errno == EINTR || errno == EAGAIN)); - - if (retval == 0) - goto timeout; - else if (retval == -1) - goto sys_error; - - /* we can still have an error connecting on windows */ - if (gst_poll_fd_has_error (fdset, fdout)) { - socklen_t len = sizeof (errno); -#ifndef G_OS_WIN32 - getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len); -#else - getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len); -#endif - goto sys_error; - } - - gst_poll_fd_ignored (fdset, fdout); - -done: - freeaddrinfo (aires); - - return GST_RTSP_OK; - - /* ERRORS */ -no_addrinfo: - { - GST_ERROR ("no addrinfo found for %s: %s", ip, gai_strerror (aierr)); - return GST_RTSP_ERROR; - } -no_family: - { - GST_ERROR ("no family found for %s", ip); - freeaddrinfo (aires); - return GST_RTSP_ERROR; - } -no_socket: - { - GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno)); - freeaddrinfo (aires); - return GST_RTSP_ESYS; - } -sys_error: - { - GST_ERROR ("system error %d (%s)", errno, g_strerror (errno)); - REMOVE_POLLFD (fdset, fdout); - freeaddrinfo (aires); - return GST_RTSP_ESYS; - } -timeout: - { - GST_ERROR ("timeout"); - REMOVE_POLLFD (fdset, fdout); - freeaddrinfo (aires); - return GST_RTSP_ETIMEOUT; - } -} - -static GstRTSPResult -setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout) -{ - gint i; - GstRTSPResult res; - gchar *ip; - gchar *uri; - gchar *value; - guint16 port, url_port; - GstRTSPUrl *url; - gchar *hostparam; - GstRTSPMessage *msg; - GstRTSPMessage response; - gboolean old_http; - - memset (&response, 0, sizeof (response)); - gst_rtsp_message_init (&response); - - /* create a random sessionid */ - for (i = 0; i < TUNNELID_LEN; i++) - conn->tunnelid[i] = g_random_int_range ('a', 'z'); - conn->tunnelid[TUNNELID_LEN - 1] = '\0'; - - url = conn->url; - /* get the port from the url */ - gst_rtsp_url_get_port (url, &url_port); - - if (conn->proxy_host) { - uri = g_strdup_printf ("http://%s:%d%s%s%s", url->host, url_port, - url->abspath, url->query ? "?" : "", url->query ? url->query : ""); - hostparam = g_strdup_printf ("%s:%d", url->host, url_port); - ip = conn->proxy_host; - port = conn->proxy_port; - } else { - uri = g_strdup_printf ("%s%s%s", url->abspath, url->query ? "?" : "", - url->query ? url->query : ""); - hostparam = NULL; - ip = conn->ip; - port = url_port; - } - - /* create the GET request for the read connection */ - GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri), - no_message); - msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST; - - if (hostparam != NULL) - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE, - conn->tunnelid); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT, - "application/x-rtsp-tunnelled"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache"); - - /* we start by writing to this fd */ - conn->writefd = &conn->fd0; - - /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP - * request from being base64 encoded */ - conn->tunneled = FALSE; - GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed); - gst_rtsp_message_free (msg); - conn->tunneled = TRUE; - - /* receive the response to the GET request */ - /* we need to temporarily set manual_http to TRUE since - * gst_rtsp_connection_receive() will treat the HTTP response as a parsing - * failure otherwise */ - old_http = conn->manual_http; - conn->manual_http = TRUE; - GST_RTSP_CHECK (gst_rtsp_connection_receive (conn, &response, timeout), - read_failed); - conn->manual_http = old_http; - - if (response.type != GST_RTSP_MESSAGE_HTTP_RESPONSE || - response.type_data.response.code != GST_RTSP_STS_OK) - goto wrong_result; - - if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS, - &value, 0) != GST_RTSP_OK) { - if (conn->proxy_host) { - /* if we use a proxy we need to change the destination url */ - g_free (url->host); - url->host = g_strdup (value); - g_free (hostparam); - hostparam = g_strdup_printf ("%s:%d", url->host, url_port); - } else { - /* and resolve the new ip address */ - if (!(ip = do_resolve (conn->ip))) - goto not_resolved; - g_free (conn->ip); - conn->ip = ip; - } - } - - /* connect to the host/port */ - res = do_connect (ip, port, &conn->fd1, conn->fdset, timeout); - if (res != GST_RTSP_OK) - goto connect_failed; - - /* this is now our writing socket */ - conn->writefd = &conn->fd1; - - /* create the POST request for the write connection */ - GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST, uri), - no_message); - msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST; - - if (hostparam != NULL) - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE, - conn->tunnelid); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT, - "application/x-rtsp-tunnelled"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES, - "Sun, 9 Jan 1972 00:00:00 GMT"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767"); - - /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP - * request from being base64 encoded */ - conn->tunneled = FALSE; - GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed); - gst_rtsp_message_free (msg); - conn->tunneled = TRUE; - -exit: - gst_rtsp_message_unset (&response); - g_free (hostparam); - g_free (uri); - - return res; - - /* ERRORS */ -no_message: - { - GST_ERROR ("failed to create request (%d)", res); - goto exit; - } -write_failed: - { - GST_ERROR ("write failed (%d)", res); - gst_rtsp_message_free (msg); - conn->tunneled = TRUE; - goto exit; - } -read_failed: - { - GST_ERROR ("read failed (%d)", res); - conn->manual_http = FALSE; - goto exit; - } -wrong_result: - { - GST_ERROR ("got failure response %d %s", response.type_data.response.code, - response.type_data.response.reason); - res = GST_RTSP_ERROR; - goto exit; - } -not_resolved: - { - GST_ERROR ("could not resolve %s", conn->ip); - res = GST_RTSP_ENET; - goto exit; - } -connect_failed: - { - GST_ERROR ("failed to connect"); - goto exit; - } -} - -/** - * gst_rtsp_connection_connect: - * @conn: a #GstRTSPConnection - * @timeout: a #GTimeVal timeout - * - * Attempt to connect to the url of @conn made with - * gst_rtsp_connection_create(). If @timeout is #NULL this function can block - * forever. If @timeout contains a valid timeout, this function will return - * #GST_RTSP_ETIMEOUT after the timeout expired. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK when a connection could be made. - */ -GstRTSPResult -gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout) -{ - GstRTSPResult res; - gchar *ip; - guint16 port; - GstRTSPUrl *url; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->fd0.fd < 0, GST_RTSP_EINVAL); - - url = conn->url; - - if (conn->proxy_host && conn->tunneled) { - if (!(ip = do_resolve (conn->proxy_host))) { - GST_ERROR ("could not resolve %s", conn->proxy_host); - goto not_resolved; - } - port = conn->proxy_port; - g_free (conn->proxy_host); - conn->proxy_host = ip; - } else { - if (!(ip = do_resolve (url->host))) { - GST_ERROR ("could not resolve %s", url->host); - goto not_resolved; - } - /* get the port from the url */ - gst_rtsp_url_get_port (url, &port); - - g_free (conn->ip); - conn->ip = ip; - } - - /* connect to the host/port */ - res = do_connect (ip, port, &conn->fd0, conn->fdset, timeout); - if (res != GST_RTSP_OK) - goto connect_failed; - - /* this is our read URL */ - conn->readfd = &conn->fd0; - - if (conn->tunneled) { - res = setup_tunneling (conn, timeout); - if (res != GST_RTSP_OK) - goto tunneling_failed; - } else { - conn->writefd = &conn->fd0; - } - - return GST_RTSP_OK; - -not_resolved: - { - return GST_RTSP_ENET; - } -connect_failed: - { - GST_ERROR ("failed to connect"); - return res; - } -tunneling_failed: - { - GST_ERROR ("failed to setup tunneling"); - return res; - } -} - -static void -auth_digest_compute_hex_urp (const gchar * username, - const gchar * realm, const gchar * password, gchar hex_urp[33]) -{ - GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5); - const gchar *digest_string; - - g_checksum_update (md5_context, (const guchar *) username, strlen (username)); - g_checksum_update (md5_context, (const guchar *) ":", 1); - g_checksum_update (md5_context, (const guchar *) realm, strlen (realm)); - g_checksum_update (md5_context, (const guchar *) ":", 1); - g_checksum_update (md5_context, (const guchar *) password, strlen (password)); - digest_string = g_checksum_get_string (md5_context); - - memset (hex_urp, 0, 33); - memcpy (hex_urp, digest_string, strlen (digest_string)); - - g_checksum_free (md5_context); -} - -static void -auth_digest_compute_response (const gchar * method, - const gchar * uri, const gchar * hex_a1, const gchar * nonce, - gchar response[33]) -{ - char hex_a2[33] = { 0, }; - GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5); - const gchar *digest_string; - - /* compute A2 */ - g_checksum_update (md5_context, (const guchar *) method, strlen (method)); - g_checksum_update (md5_context, (const guchar *) ":", 1); - g_checksum_update (md5_context, (const guchar *) uri, strlen (uri)); - digest_string = g_checksum_get_string (md5_context); - memcpy (hex_a2, digest_string, strlen (digest_string)); - - /* compute KD */ - g_checksum_reset (md5_context); - g_checksum_update (md5_context, (const guchar *) hex_a1, strlen (hex_a1)); - g_checksum_update (md5_context, (const guchar *) ":", 1); - g_checksum_update (md5_context, (const guchar *) nonce, strlen (nonce)); - g_checksum_update (md5_context, (const guchar *) ":", 1); - - g_checksum_update (md5_context, (const guchar *) hex_a2, 32); - digest_string = g_checksum_get_string (md5_context); - memset (response, 0, 33); - memcpy (response, digest_string, strlen (digest_string)); - - g_checksum_free (md5_context); -} - -static void -add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message) -{ - switch (conn->auth_method) { - case GST_RTSP_AUTH_BASIC:{ - gchar *user_pass; - gchar *user_pass64; - gchar *auth_string; - - user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd); - user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass)); - auth_string = g_strdup_printf ("Basic %s", user_pass64); - - gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION, - auth_string); - - g_free (user_pass); - g_free (user_pass64); - break; - } - case GST_RTSP_AUTH_DIGEST:{ - gchar response[33], hex_urp[33]; - gchar *auth_string, *auth_string2; - gchar *realm; - gchar *nonce; - gchar *opaque; - const gchar *uri; - const gchar *method; - - /* we need to have some params set */ - if (conn->auth_params == NULL) - break; - - /* we need the realm and nonce */ - realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm"); - nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce"); - if (realm == NULL || nonce == NULL) - break; - - auth_digest_compute_hex_urp (conn->username, realm, conn->passwd, - hex_urp); - - method = gst_rtsp_method_as_text (message->type_data.request.method); - uri = message->type_data.request.uri; - - /* Assume no qop, algorithm=md5, stale=false */ - /* For algorithm MD5, a1 = urp. */ - auth_digest_compute_response (method, uri, hex_urp, nonce, response); - auth_string = g_strdup_printf ("Digest username=\"%s\", " - "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", - conn->username, realm, nonce, uri, response); - - opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque"); - if (opaque) { - auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string, - opaque); - g_free (auth_string); - auth_string = auth_string2; - } - gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION, - auth_string); - break; - } - default: - /* Nothing to do */ - break; - } -} - -static void -gen_date_string (gchar * date_string, guint len) -{ - GTimeVal tv; - time_t t; -#ifdef HAVE_GMTIME_R - struct tm tm_; -#endif - - g_get_current_time (&tv); - t = (time_t) tv.tv_sec; - -#ifdef HAVE_GMTIME_R - strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&t, &tm_)); -#else - strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime (&t)); -#endif -} - -static GstRTSPResult -write_bytes (gint fd, const guint8 * buffer, guint * idx, guint size) -{ - guint left; - - if (G_UNLIKELY (*idx > size)) - return GST_RTSP_ERROR; - - left = size - *idx; - - while (left) { - gint r; - - r = WRITE_SOCKET (fd, &buffer[*idx], left); - if (G_UNLIKELY (r == 0)) { - return GST_RTSP_EINTR; - } else if (G_UNLIKELY (r < 0)) { - if (ERRNO_IS_EAGAIN) - return GST_RTSP_EINTR; - if (!ERRNO_IS_EINTR) - return GST_RTSP_ESYS; - } else { - left -= r; - *idx += r; - } - } - return GST_RTSP_OK; -} - -static gint -fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size) -{ - gint out = 0; - - if (G_UNLIKELY (conn->initial_buffer != NULL)) { - gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]); - - out = MIN (left, size); - memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out); - - if (left == (gsize) out) { - g_free (conn->initial_buffer); - conn->initial_buffer = NULL; - conn->initial_buffer_offset = 0; - } else - conn->initial_buffer_offset += out; - } - - if (G_LIKELY (size > (guint) out)) { - gint r; - - r = READ_SOCKET (conn->readfd->fd, &buffer[out], size - out); - if (r <= 0) { - if (out == 0) - out = r; - } else - out += r; - } - - return out; -} - -static gint -fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size) -{ - DecodeCtx *ctx = conn->ctxp; - gint out = 0; - - if (ctx) { - while (size > 0) { - guint8 in[sizeof (ctx->out) * 4 / 3]; - gint r; - - while (size > 0 && ctx->cout < ctx->coutl) { - /* we have some leftover bytes */ - *buffer++ = ctx->out[ctx->cout++]; - size--; - out++; - } - - /* got what we needed? */ - if (size == 0) - break; - - /* try to read more bytes */ - r = fill_raw_bytes (conn, in, sizeof (in)); - if (r <= 0) { - if (out == 0) - out = r; - break; - } - - ctx->cout = 0; - ctx->coutl = - g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state, - &ctx->save); - } - } else { - out = fill_raw_bytes (conn, buffer, size); - } - - return out; -} - -static GstRTSPResult -read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size) -{ - guint left; - - if (G_UNLIKELY (*idx > size)) - return GST_RTSP_ERROR; - - left = size - *idx; - - while (left) { - gint r; - - r = fill_bytes (conn, &buffer[*idx], left); - if (G_UNLIKELY (r == 0)) { - return GST_RTSP_EEOF; - } else if (G_UNLIKELY (r < 0)) { - if (ERRNO_IS_EAGAIN) - return GST_RTSP_EINTR; - if (!ERRNO_IS_EINTR) - return GST_RTSP_ESYS; - } else { - left -= r; - *idx += r; - } - } - return GST_RTSP_OK; -} - -/* The code below tries to handle clients using \r, \n or \r\n to indicate the - * end of a line. It even does its best to handle clients which mix them (even - * though this is a really stupid idea (tm).) It also handles Line White Space - * (LWS), where a line end followed by whitespace is considered LWS. This is - * the method used in RTSP (and HTTP) to break long lines. - */ -static GstRTSPResult -read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size) -{ - while (TRUE) { - guint8 c; - gint r; - - if (conn->read_ahead == READ_AHEAD_EOH) { - /* the last call to read_line() already determined that we have reached - * the end of the headers, so convey that information now */ - conn->read_ahead = 0; - break; - } else if (conn->read_ahead == READ_AHEAD_CRLF) { - /* the last call to read_line() left off after having read \r\n */ - c = '\n'; - } else if (conn->read_ahead == READ_AHEAD_CRLFCR) { - /* the last call to read_line() left off after having read \r\n\r */ - c = '\r'; - } else if (conn->read_ahead != 0) { - /* the last call to read_line() left us with a character to start with */ - c = (guint8) conn->read_ahead; - conn->read_ahead = 0; - } else { - /* read the next character */ - r = fill_bytes (conn, &c, 1); - if (G_UNLIKELY (r == 0)) { - return GST_RTSP_EEOF; - } else if (G_UNLIKELY (r < 0)) { - if (ERRNO_IS_EAGAIN) - return GST_RTSP_EINTR; - if (!ERRNO_IS_EINTR) - return GST_RTSP_ESYS; - continue; - } - } - - /* special treatment of line endings */ - if (c == '\r' || c == '\n') { - guint8 read_ahead; - - retry: - /* need to read ahead one more character to know what to do... */ - r = fill_bytes (conn, &read_ahead, 1); - if (G_UNLIKELY (r == 0)) { - return GST_RTSP_EEOF; - } else if (G_UNLIKELY (r < 0)) { - if (ERRNO_IS_EAGAIN) { - /* remember the original character we read and try again next time */ - if (conn->read_ahead == 0) - conn->read_ahead = c; - return GST_RTSP_EINTR; - } - if (!ERRNO_IS_EINTR) - return GST_RTSP_ESYS; - goto retry; - } - - if (read_ahead == ' ' || read_ahead == '\t') { - if (conn->read_ahead == READ_AHEAD_CRLFCR) { - /* got \r\n\r followed by whitespace, treat it as a normal line - * followed by one starting with LWS */ - conn->read_ahead = read_ahead; - break; - } else { - /* got LWS, change the line ending to a space and continue */ - c = ' '; - conn->read_ahead = read_ahead; - } - } else if (conn->read_ahead == READ_AHEAD_CRLFCR) { - if (read_ahead == '\r' || read_ahead == '\n') { - /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */ - conn->read_ahead = READ_AHEAD_EOH; - break; - } else { - /* got \r\n\r followed by something else, this is not really - * supported since we have probably just eaten the first character - * of the body or the next message, so just ignore the second \r - * and live with it... */ - conn->read_ahead = read_ahead; - break; - } - } else if (conn->read_ahead == READ_AHEAD_CRLF) { - if (read_ahead == '\r') { - /* got \r\n\r so far, need one more character... */ - conn->read_ahead = READ_AHEAD_CRLFCR; - goto retry; - } else if (read_ahead == '\n') { - /* got \r\n\n, treat it as the end of the headers */ - conn->read_ahead = READ_AHEAD_EOH; - break; - } else { - /* found the end of a line, keep read_ahead for the next line */ - conn->read_ahead = read_ahead; - break; - } - } else if (c == read_ahead) { - /* got double \r or \n, treat it as the end of the headers */ - conn->read_ahead = READ_AHEAD_EOH; - break; - } else if (c == '\r' && read_ahead == '\n') { - /* got \r\n so far, still need more to know what to do... */ - conn->read_ahead = READ_AHEAD_CRLF; - goto retry; - } else { - /* found the end of a line, keep read_ahead for the next line */ - conn->read_ahead = read_ahead; - break; - } - } - - if (G_LIKELY (*idx < size - 1)) - buffer[(*idx)++] = c; - } - buffer[*idx] = '\0'; - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_write: - * @conn: a #GstRTSPConnection - * @data: the data to write - * @size: the size of @data - * @timeout: a timeout value or #NULL - * - * Attempt to write @size bytes of @data to the connected @conn, blocking up to - * the specified @timeout. @timeout can be #NULL, in which case this function - * might block forever. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data, - guint size, GTimeVal * timeout) -{ - guint offset; - gint retval; - GstClockTime to; - GstRTSPResult res; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL); - - gst_poll_set_controllable (conn->fdset, TRUE); - gst_poll_fd_ctl_write (conn->fdset, conn->writefd, TRUE); - gst_poll_fd_ctl_read (conn->fdset, conn->readfd, FALSE); - /* clear all previous poll results */ - gst_poll_fd_ignored (conn->fdset, conn->writefd); - gst_poll_fd_ignored (conn->fdset, conn->readfd); - - to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE; - - offset = 0; - - while (TRUE) { - /* try to write */ - res = write_bytes (conn->writefd->fd, data, &offset, size); - if (G_LIKELY (res == GST_RTSP_OK)) - break; - if (G_UNLIKELY (res != GST_RTSP_EINTR)) - goto write_error; - - /* not all is written, wait until we can write more */ - do { - retval = gst_poll_wait (conn->fdset, to); - } while (retval == -1 && (errno == EINTR || errno == EAGAIN)); - - if (G_UNLIKELY (retval == 0)) - goto timeout; - - if (G_UNLIKELY (retval == -1)) { - if (errno == EBUSY) - goto stopped; - else - goto select_error; - } - } - return GST_RTSP_OK; - - /* ERRORS */ -timeout: - { - return GST_RTSP_ETIMEOUT; - } -select_error: - { - return GST_RTSP_ESYS; - } -stopped: - { - return GST_RTSP_EINTR; - } -write_error: - { - return res; - } -} - -static GString * -message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message) -{ - GString *str = NULL; - - str = g_string_new (""); - - switch (message->type) { - case GST_RTSP_MESSAGE_REQUEST: - /* create request string, add CSeq */ - g_string_append_printf (str, "%s %s RTSP/1.0\r\n" - "CSeq: %d\r\n", - gst_rtsp_method_as_text (message->type_data.request.method), - message->type_data.request.uri, conn->cseq++); - /* add session id if we have one */ - if (conn->session_id[0] != '\0') { - gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1); - gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION, - conn->session_id); - } - /* add any authentication headers */ - add_auth_header (conn, message); - break; - case GST_RTSP_MESSAGE_RESPONSE: - /* create response string */ - g_string_append_printf (str, "RTSP/1.0 %d %s\r\n", - message->type_data.response.code, message->type_data.response.reason); - break; - case GST_RTSP_MESSAGE_HTTP_REQUEST: - /* create request string */ - g_string_append_printf (str, "%s %s HTTP/%s\r\n", - gst_rtsp_method_as_text (message->type_data.request.method), - message->type_data.request.uri, - gst_rtsp_version_as_text (message->type_data.request.version)); - /* add any authentication headers */ - add_auth_header (conn, message); - break; - case GST_RTSP_MESSAGE_HTTP_RESPONSE: - /* create response string */ - g_string_append_printf (str, "HTTP/%s %d %s\r\n", - gst_rtsp_version_as_text (message->type_data.request.version), - message->type_data.response.code, message->type_data.response.reason); - break; - case GST_RTSP_MESSAGE_DATA: - { - guint8 data_header[4]; - - /* prepare data header */ - data_header[0] = '$'; - data_header[1] = message->type_data.data.channel; - data_header[2] = (message->body_size >> 8) & 0xff; - data_header[3] = message->body_size & 0xff; - - /* create string with header and data */ - str = g_string_append_len (str, (gchar *) data_header, 4); - str = - g_string_append_len (str, (gchar *) message->body, - message->body_size); - break; - } - default: - g_string_free (str, TRUE); - g_return_val_if_reached (NULL); - break; - } - - /* append headers and body */ - if (message->type != GST_RTSP_MESSAGE_DATA) { - gchar date_string[100]; - - gen_date_string (date_string, sizeof (date_string)); - - /* add date header */ - gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1); - gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string); - - /* append headers */ - gst_rtsp_message_append_headers (message, str); - - /* append Content-Length and body if needed */ - if (message->body != NULL && message->body_size > 0) { - gchar *len; - - len = g_strdup_printf ("%d", message->body_size); - g_string_append_printf (str, "%s: %s\r\n", - gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len); - g_free (len); - /* header ends here */ - g_string_append (str, "\r\n"); - str = - g_string_append_len (str, (gchar *) message->body, - message->body_size); - } else { - /* just end headers */ - g_string_append (str, "\r\n"); - } - } - - return str; -} - -/** - * gst_rtsp_connection_send: - * @conn: a #GstRTSPConnection - * @message: the message to send - * @timeout: a timeout value or #NULL - * - * Attempt to send @message to the connected @conn, blocking up to - * the specified @timeout. @timeout can be #NULL, in which case this function - * might block forever. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message, - GTimeVal * timeout) -{ - GString *string = NULL; - GstRTSPResult res; - gchar *str; - gsize len; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); - - if (G_UNLIKELY (!(string = message_to_string (conn, message)))) - goto no_message; - - if (conn->tunneled) { - str = g_base64_encode ((const guchar *) string->str, string->len); - g_string_free (string, TRUE); - len = strlen (str); - } else { - str = string->str; - len = string->len; - g_string_free (string, FALSE); - } - - /* write request */ - res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout); - - g_free (str); - - return res; - -no_message: - { - g_warning ("Wrong message"); - return GST_RTSP_EINVAL; - } -} - -static GstRTSPResult -parse_string (gchar * dest, gint size, gchar ** src) -{ - GstRTSPResult res = GST_RTSP_OK; - gint idx; - - idx = 0; - /* skip spaces */ - while (g_ascii_isspace (**src)) - (*src)++; - - while (!g_ascii_isspace (**src) && **src != '\0') { - if (idx < size - 1) - dest[idx++] = **src; - else - res = GST_RTSP_EPARSE; - (*src)++; - } - if (size > 0) - dest[idx] = '\0'; - - return res; -} - -static GstRTSPResult -parse_protocol_version (gchar * protocol, GstRTSPMsgType * type, - GstRTSPVersion * version) -{ - GstRTSPResult res = GST_RTSP_OK; - gchar *ver; - - if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) { - guint major; - guint minor; - gchar dummychar; - - *ver++ = '\0'; - - /* the version number must be formatted as X.Y with nothing following */ - if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2) - res = GST_RTSP_EPARSE; - - if (g_ascii_strcasecmp (protocol, "RTSP") == 0) { - if (major != 1 || minor != 0) { - *version = GST_RTSP_VERSION_INVALID; - res = GST_RTSP_ERROR; - } - } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) { - if (*type == GST_RTSP_MESSAGE_REQUEST) - *type = GST_RTSP_MESSAGE_HTTP_REQUEST; - else if (*type == GST_RTSP_MESSAGE_RESPONSE) - *type = GST_RTSP_MESSAGE_HTTP_RESPONSE; - - if (major == 1 && minor == 1) { - *version = GST_RTSP_VERSION_1_1; - } else if (major != 1 || minor != 0) { - *version = GST_RTSP_VERSION_INVALID; - res = GST_RTSP_ERROR; - } - } else - res = GST_RTSP_EPARSE; - } else - res = GST_RTSP_EPARSE; - - return res; -} - -static GstRTSPResult -parse_response_status (guint8 * buffer, GstRTSPMessage * msg) -{ - GstRTSPResult res = GST_RTSP_OK; - GstRTSPResult res2; - gchar versionstr[20]; - gchar codestr[4]; - gint code; - gchar *bptr; - - bptr = (gchar *) buffer; - - if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK) - res = GST_RTSP_EPARSE; - - if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK) - res = GST_RTSP_EPARSE; - code = atoi (codestr); - if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600)) - res = GST_RTSP_EPARSE; - - while (g_ascii_isspace (*bptr)) - bptr++; - - if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr, - NULL) != GST_RTSP_OK)) - res = GST_RTSP_EPARSE; - - res2 = parse_protocol_version (versionstr, &msg->type, - &msg->type_data.response.version); - if (G_LIKELY (res == GST_RTSP_OK)) - res = res2; - - return res; -} - -static GstRTSPResult -parse_request_line (guint8 * buffer, GstRTSPMessage * msg) -{ - GstRTSPResult res = GST_RTSP_OK; - GstRTSPResult res2; - gchar versionstr[20]; - gchar methodstr[20]; - gchar urlstr[4096]; - gchar *bptr; - GstRTSPMethod method; - - bptr = (gchar *) buffer; - - if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK) - res = GST_RTSP_EPARSE; - method = gst_rtsp_find_method (methodstr); - - if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK) - res = GST_RTSP_EPARSE; - if (G_UNLIKELY (*urlstr == '\0')) - res = GST_RTSP_EPARSE; - - if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK) - res = GST_RTSP_EPARSE; - - if (G_UNLIKELY (*bptr != '\0')) - res = GST_RTSP_EPARSE; - - if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method, - urlstr) != GST_RTSP_OK)) - res = GST_RTSP_EPARSE; - - res2 = parse_protocol_version (versionstr, &msg->type, - &msg->type_data.request.version); - if (G_LIKELY (res == GST_RTSP_OK)) - res = res2; - - if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) { - /* GET and POST are not allowed as RTSP methods */ - if (msg->type_data.request.method == GST_RTSP_GET || - msg->type_data.request.method == GST_RTSP_POST) { - msg->type_data.request.method = GST_RTSP_INVALID; - if (res == GST_RTSP_OK) - res = GST_RTSP_ERROR; - } - } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) { - /* only GET and POST are allowed as HTTP methods */ - if (msg->type_data.request.method != GST_RTSP_GET && - msg->type_data.request.method != GST_RTSP_POST) { - msg->type_data.request.method = GST_RTSP_INVALID; - if (res == GST_RTSP_OK) - res = GST_RTSP_ERROR; - } - } - - return res; -} - -/* parsing lines means reading a Key: Value pair */ -static GstRTSPResult -parse_line (guint8 * buffer, GstRTSPMessage * msg) -{ - GstRTSPHeaderField field; - gchar *line = (gchar *) buffer; - gchar *value; - - if ((value = strchr (line, ':')) == NULL || value == line) - goto parse_error; - - /* trim space before the colon */ - if (value[-1] == ' ') - value[-1] = '\0'; - - /* replace the colon with a NUL */ - *value++ = '\0'; - - /* find the header */ - field = gst_rtsp_find_header_field (line); - if (field == GST_RTSP_HDR_INVALID) - goto done; - - /* split up the value in multiple key:value pairs if it contains comma(s) */ - while (*value != '\0') { - gchar *next_value; - gchar *comma = NULL; - gboolean quoted = FALSE; - guint comment = 0; - - /* trim leading space */ - if (*value == ' ') - value++; - - /* for headers which may not appear multiple times, and thus may not - * contain multiple values on the same line, we can short-circuit the loop - * below and the entire value results in just one key:value pair*/ - if (!gst_rtsp_header_allow_multiple (field)) - next_value = value + strlen (value); - else - next_value = value; - - /* find the next value, taking special care of quotes and comments */ - while (*next_value != '\0') { - if ((quoted || comment != 0) && *next_value == '\\' && - next_value[1] != '\0') - next_value++; - else if (comment == 0 && *next_value == '"') - quoted = !quoted; - else if (!quoted && *next_value == '(') - comment++; - else if (comment != 0 && *next_value == ')') - comment--; - else if (!quoted && comment == 0) { - /* To quote RFC 2068: "User agents MUST take special care in parsing - * the WWW-Authenticate field value if it contains more than one - * challenge, or if more than one WWW-Authenticate header field is - * provided, since the contents of a challenge may itself contain a - * comma-separated list of authentication parameters." - * - * What this means is that we cannot just look for an unquoted comma - * when looking for multiple values in Proxy-Authenticate and - * WWW-Authenticate headers. Instead we need to look for the sequence - * "comma [space] token space token" before we can split after the - * comma... - */ - if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE || - field == GST_RTSP_HDR_WWW_AUTHENTICATE) { - if (*next_value == ',') { - if (next_value[1] == ' ') { - /* skip any space following the comma so we do not mistake it for - * separating between two tokens */ - next_value++; - } - comma = next_value; - } else if (*next_value == ' ' && next_value[1] != ',' && - next_value[1] != '=' && comma != NULL) { - next_value = comma; - comma = NULL; - break; - } - } else if (*next_value == ',') - break; - } - - next_value++; - } - - /* trim space */ - if (value != next_value && next_value[-1] == ' ') - next_value[-1] = '\0'; - - if (*next_value != '\0') - *next_value++ = '\0'; - - /* add the key:value pair */ - if (*value != '\0') - gst_rtsp_message_add_header (msg, field, value); - - value = next_value; - } - -done: - return GST_RTSP_OK; - - /* ERRORS */ -parse_error: - { - return GST_RTSP_EPARSE; - } -} - -/* convert all consecutive whitespace to a single space */ -static void -normalize_line (guint8 * buffer) -{ - while (*buffer) { - if (g_ascii_isspace (*buffer)) { - guint8 *tmp; - - *buffer++ = ' '; - for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) { - } - if (buffer != tmp) - memmove (buffer, tmp, strlen ((gchar *) tmp) + 1); - } else { - buffer++; - } - } -} - -/* returns: - * GST_RTSP_OK when a complete message was read. - * GST_RTSP_EEOF: when the socket is closed - * GST_RTSP_EINTR: when more data is needed. - * GST_RTSP_..: some other error occured. - */ -static GstRTSPResult -build_next (GstRTSPBuilder * builder, GstRTSPMessage * message, - GstRTSPConnection * conn) -{ - GstRTSPResult res; - - while (TRUE) { - switch (builder->state) { - case STATE_START: - builder->offset = 0; - res = - read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1); - if (res != GST_RTSP_OK) - goto done; - - /* we have 1 bytes now and we can see if this is a data message or - * not */ - if (builder->buffer[0] == '$') { - /* data message, prepare for the header */ - builder->state = STATE_DATA_HEADER; - } else { - builder->line = 0; - builder->state = STATE_READ_LINES; - } - break; - case STATE_DATA_HEADER: - { - res = - read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4); - if (res != GST_RTSP_OK) - goto done; - - gst_rtsp_message_init_data (message, builder->buffer[1]); - - builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3]; - builder->body_data = g_malloc (builder->body_len + 1); - builder->body_data[builder->body_len] = '\0'; - builder->offset = 0; - builder->state = STATE_DATA_BODY; - break; - } - case STATE_DATA_BODY: - { - res = - read_bytes (conn, builder->body_data, &builder->offset, - builder->body_len); - if (res != GST_RTSP_OK) - goto done; - - /* we have the complete body now, store in the message adjusting the - * length to include the traling '\0' */ - gst_rtsp_message_take_body (message, - (guint8 *) builder->body_data, builder->body_len + 1); - builder->body_data = NULL; - builder->body_len = 0; - - builder->state = STATE_END; - break; - } - case STATE_READ_LINES: - { - res = read_line (conn, builder->buffer, &builder->offset, - sizeof (builder->buffer)); - if (res != GST_RTSP_OK) - goto done; - - /* we have a regular response */ - if (builder->buffer[0] == '\0') { - gchar *hdrval; - - /* empty line, end of message header */ - /* see if there is a Content-Length header, but ignore it if this - * is a POST request with an x-sessioncookie header */ - if (gst_rtsp_message_get_header (message, - GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK && - (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST || - message->type_data.request.method != GST_RTSP_POST || - gst_rtsp_message_get_header (message, - GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) { - /* there is, prepare to read the body */ - builder->body_len = atol (hdrval); - builder->body_data = g_malloc (builder->body_len + 1); - builder->body_data[builder->body_len] = '\0'; - builder->offset = 0; - builder->state = STATE_DATA_BODY; - } else { - builder->state = STATE_END; - } - break; - } - - /* we have a line */ - normalize_line (builder->buffer); - if (builder->line == 0) { - /* first line, check for response status */ - if (memcmp (builder->buffer, "RTSP", 4) == 0 || - memcmp (builder->buffer, "HTTP", 4) == 0) { - builder->status = parse_response_status (builder->buffer, message); - } else { - builder->status = parse_request_line (builder->buffer, message); - } - } else { - /* else just parse the line */ - res = parse_line (builder->buffer, message); - if (res != GST_RTSP_OK) - builder->status = res; - } - builder->line++; - builder->offset = 0; - break; - } - case STATE_END: - { - gchar *session_cookie; - gchar *session_id; - - if (message->type == GST_RTSP_MESSAGE_DATA) { - /* data messages don't have headers */ - res = GST_RTSP_OK; - goto done; - } - - /* save the tunnel session in the connection */ - if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST && - !conn->manual_http && - conn->tstate == TUNNEL_STATE_NONE && - gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE, - &session_cookie, 0) == GST_RTSP_OK) { - strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN); - conn->tunnelid[TUNNELID_LEN - 1] = '\0'; - conn->tunneled = TRUE; - } - - /* save session id in the connection for further use */ - if (message->type == GST_RTSP_MESSAGE_RESPONSE && - gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION, - &session_id, 0) == GST_RTSP_OK) { - gint maxlen, i; - - maxlen = sizeof (conn->session_id) - 1; - /* the sessionid can have attributes marked with ; - * Make sure we strip them */ - for (i = 0; session_id[i] != '\0'; i++) { - if (session_id[i] == ';') { - maxlen = i; - /* parse timeout */ - do { - i++; - } while (g_ascii_isspace (session_id[i])); - if (g_str_has_prefix (&session_id[i], "timeout=")) { - gint to; - - /* if we parsed something valid, configure */ - if ((to = atoi (&session_id[i + 8])) > 0) - conn->timeout = to; - } - break; - } - } - - /* make sure to not overflow */ - strncpy (conn->session_id, session_id, maxlen); - conn->session_id[maxlen] = '\0'; - } - res = builder->status; - goto done; - } - default: - res = GST_RTSP_ERROR; - break; - } - } -done: - return res; -} - -/** - * gst_rtsp_connection_read: - * @conn: a #GstRTSPConnection - * @data: the data to read - * @size: the size of @data - * @timeout: a timeout value or #NULL - * - * Attempt to read @size bytes into @data from the connected @conn, blocking up to - * the specified @timeout. @timeout can be #NULL, in which case this function - * might block forever. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size, - GTimeVal * timeout) -{ - guint offset; - gint retval; - GstClockTime to; - GstRTSPResult res; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL); - - if (G_UNLIKELY (size == 0)) - return GST_RTSP_OK; - - offset = 0; - - /* configure timeout if any */ - to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE; - - gst_poll_set_controllable (conn->fdset, TRUE); - gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE); - gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE); - - while (TRUE) { - res = read_bytes (conn, data, &offset, size); - if (G_UNLIKELY (res == GST_RTSP_EEOF)) - goto eof; - if (G_LIKELY (res == GST_RTSP_OK)) - break; - if (G_UNLIKELY (res != GST_RTSP_EINTR)) - goto read_error; - - do { - retval = gst_poll_wait (conn->fdset, to); - } while (retval == -1 && (errno == EINTR || errno == EAGAIN)); - - /* check for timeout */ - if (G_UNLIKELY (retval == 0)) - goto select_timeout; - - if (G_UNLIKELY (retval == -1)) { - if (errno == EBUSY) - goto stopped; - else - goto select_error; - } - gst_poll_set_controllable (conn->fdset, FALSE); - } - return GST_RTSP_OK; - - /* ERRORS */ -select_error: - { - return GST_RTSP_ESYS; - } -select_timeout: - { - return GST_RTSP_ETIMEOUT; - } -stopped: - { - return GST_RTSP_EINTR; - } -eof: - { - return GST_RTSP_EEOF; - } -read_error: - { - return res; - } -} - -static GstRTSPMessage * -gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code, - const GstRTSPMessage * request) -{ - GstRTSPMessage *msg; - GstRTSPResult res; - - if (gst_rtsp_status_as_text (code) == NULL) - code = GST_RTSP_STS_INTERNAL_SERVER_ERROR; - - GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request), - no_message); - - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER, - "GStreamer RTSP Server"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store"); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache"); - - if (code == GST_RTSP_STS_OK) { - if (conn->ip) - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS, - conn->ip); - gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE, - "application/x-rtsp-tunnelled"); - } - - return msg; - - /* ERRORS */ -no_message: - { - return NULL; - } -} - -/** - * gst_rtsp_connection_receive: - * @conn: a #GstRTSPConnection - * @message: the message to read - * @timeout: a timeout value or #NULL - * - * Attempt to read into @message from the connected @conn, blocking up to - * the specified @timeout. @timeout can be #NULL, in which case this function - * might block forever. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message, - GTimeVal * timeout) -{ - GstRTSPResult res; - GstRTSPBuilder builder; - gint retval; - GstClockTime to; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL); - - /* configure timeout if any */ - to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE; - - gst_poll_set_controllable (conn->fdset, TRUE); - gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE); - gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE); - - memset (&builder, 0, sizeof (GstRTSPBuilder)); - while (TRUE) { - res = build_next (&builder, message, conn); - if (G_UNLIKELY (res == GST_RTSP_EEOF)) - goto eof; - else if (G_LIKELY (res == GST_RTSP_OK)) { - if (!conn->manual_http) { - if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) { - if (conn->tstate == TUNNEL_STATE_NONE && - message->type_data.request.method == GST_RTSP_GET) { - GstRTSPMessage *response; - - conn->tstate = TUNNEL_STATE_GET; - - /* tunnel GET request, we can reply now */ - response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message); - res = gst_rtsp_connection_send (conn, response, timeout); - gst_rtsp_message_free (response); - if (res == GST_RTSP_OK) - res = GST_RTSP_ETGET; - goto cleanup; - } else if (conn->tstate == TUNNEL_STATE_NONE && - message->type_data.request.method == GST_RTSP_POST) { - conn->tstate = TUNNEL_STATE_POST; - - /* tunnel POST request, the caller now has to link the two - * connections. */ - res = GST_RTSP_ETPOST; - goto cleanup; - } else { - res = GST_RTSP_EPARSE; - goto cleanup; - } - } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) { - res = GST_RTSP_EPARSE; - goto cleanup; - } - } - - break; - } else if (G_UNLIKELY (res != GST_RTSP_EINTR)) - goto read_error; - - do { - retval = gst_poll_wait (conn->fdset, to); - } while (retval == -1 && (errno == EINTR || errno == EAGAIN)); - - /* check for timeout */ - if (G_UNLIKELY (retval == 0)) - goto select_timeout; - - if (G_UNLIKELY (retval == -1)) { - if (errno == EBUSY) - goto stopped; - else - goto select_error; - } - gst_poll_set_controllable (conn->fdset, FALSE); - } - - /* we have a message here */ - build_reset (&builder); - - return GST_RTSP_OK; - - /* ERRORS */ -select_error: - { - res = GST_RTSP_ESYS; - goto cleanup; - } -select_timeout: - { - res = GST_RTSP_ETIMEOUT; - goto cleanup; - } -stopped: - { - res = GST_RTSP_EINTR; - goto cleanup; - } -eof: - { - res = GST_RTSP_EEOF; - goto cleanup; - } -read_error: -cleanup: - { - build_reset (&builder); - gst_rtsp_message_unset (message); - return res; - } -} - -/** - * gst_rtsp_connection_close: - * @conn: a #GstRTSPConnection - * - * Close the connected @conn. After this call, the connection is in the same - * state as when it was first created. - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_close (GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - g_free (conn->ip); - conn->ip = NULL; - - conn->read_ahead = 0; - - g_free (conn->initial_buffer); - conn->initial_buffer = NULL; - conn->initial_buffer_offset = 0; - - REMOVE_POLLFD (conn->fdset, &conn->fd0); - REMOVE_POLLFD (conn->fdset, &conn->fd1); - conn->writefd = NULL; - conn->readfd = NULL; - conn->tunneled = FALSE; - conn->tstate = TUNNEL_STATE_NONE; - conn->ctxp = NULL; - g_free (conn->username); - conn->username = NULL; - g_free (conn->passwd); - conn->passwd = NULL; - gst_rtsp_connection_clear_auth_params (conn); - conn->timeout = 60; - conn->cseq = 0; - conn->session_id[0] = '\0'; - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_free: - * @conn: a #GstRTSPConnection - * - * Close and free @conn. - * - * Returns: #GST_RTSP_OK on success. - */ -GstRTSPResult -gst_rtsp_connection_free (GstRTSPConnection * conn) -{ - GstRTSPResult res; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - res = gst_rtsp_connection_close (conn); - gst_poll_free (conn->fdset); - g_timer_destroy (conn->timer); - gst_rtsp_url_free (conn->url); - g_free (conn->proxy_host); - g_free (conn); -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return res; -} - -/** - * gst_rtsp_connection_poll: - * @conn: a #GstRTSPConnection - * @events: a bitmask of #GstRTSPEvent flags to check - * @revents: location for result flags - * @timeout: a timeout - * - * Wait up to the specified @timeout for the connection to become available for - * at least one of the operations specified in @events. When the function returns - * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on - * @conn. - * - * @timeout can be #NULL, in which case this function might block forever. - * - * This function can be cancelled with gst_rtsp_connection_flush(). - * - * Returns: #GST_RTSP_OK on success. - * - * Since: 0.10.15 - */ -GstRTSPResult -gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events, - GstRTSPEvent * revents, GTimeVal * timeout) -{ - GstClockTime to; - gint retval; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (events != 0, GST_RTSP_EINVAL); - g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL); - - gst_poll_set_controllable (conn->fdset, TRUE); - - /* add fd to writer set when asked to */ - gst_poll_fd_ctl_write (conn->fdset, conn->writefd, - events & GST_RTSP_EV_WRITE); - - /* add fd to reader set when asked to */ - gst_poll_fd_ctl_read (conn->fdset, conn->readfd, events & GST_RTSP_EV_READ); - - /* configure timeout if any */ - to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE; - - do { - retval = gst_poll_wait (conn->fdset, to); - } while (retval == -1 && (errno == EINTR || errno == EAGAIN)); - - if (G_UNLIKELY (retval == 0)) - goto select_timeout; - - if (G_UNLIKELY (retval == -1)) { - if (errno == EBUSY) - goto stopped; - else - goto select_error; - } - - *revents = 0; - if (events & GST_RTSP_EV_READ) { - if (gst_poll_fd_can_read (conn->fdset, conn->readfd)) - *revents |= GST_RTSP_EV_READ; - } - if (events & GST_RTSP_EV_WRITE) { - if (gst_poll_fd_can_write (conn->fdset, conn->writefd)) - *revents |= GST_RTSP_EV_WRITE; - } - return GST_RTSP_OK; - - /* ERRORS */ -select_timeout: - { - return GST_RTSP_ETIMEOUT; - } -select_error: - { - return GST_RTSP_ESYS; - } -stopped: - { - return GST_RTSP_EINTR; - } -} - -/** - * gst_rtsp_connection_next_timeout: - * @conn: a #GstRTSPConnection - * @timeout: a timeout - * - * Calculate the next timeout for @conn, storing the result in @timeout. - * - * Returns: #GST_RTSP_OK. - */ -GstRTSPResult -gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout) -{ - gdouble elapsed; - glong sec; - gulong usec; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL); - - elapsed = g_timer_elapsed (conn->timer, &usec); - if (elapsed >= conn->timeout) { - sec = 0; - usec = 0; - } else { - sec = conn->timeout - elapsed; - } - - timeout->tv_sec = sec; - timeout->tv_usec = usec; - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_reset_timeout: - * @conn: a #GstRTSPConnection - * - * Reset the timeout of @conn. - * - * Returns: #GST_RTSP_OK. - */ -GstRTSPResult -gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - g_timer_start (conn->timer); - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_flush: - * @conn: a #GstRTSPConnection - * @flush: start or stop the flush - * - * Start or stop the flushing action on @conn. When flushing, all current - * and future actions on @conn will return #GST_RTSP_EINTR until the connection - * is set to non-flushing mode again. - * - * Returns: #GST_RTSP_OK. - */ -GstRTSPResult -gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - gst_poll_set_flushing (conn->fdset, flush); - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_set_proxy: - * @conn: a #GstRTSPConnection - * @host: the proxy host - * @port: the proxy port - * - * Set the proxy host and port. - * - * Returns: #GST_RTSP_OK. - * - * Since: 0.10.23 - */ -GstRTSPResult -gst_rtsp_connection_set_proxy (GstRTSPConnection * conn, - const gchar * host, guint port) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - g_free (conn->proxy_host); - conn->proxy_host = g_strdup (host); - conn->proxy_port = port; - - return GST_RTSP_OK; -} - -/** - * gst_rtsp_connection_set_auth: - * @conn: a #GstRTSPConnection - * @method: authentication method - * @user: the user - * @pass: the password - * - * Configure @conn for authentication mode @method with @user and @pass as the - * user and password respectively. - * - * Returns: #GST_RTSP_OK. - */ -GstRTSPResult -gst_rtsp_connection_set_auth (GstRTSPConnection * conn, - GstRTSPAuthMethod method, const gchar * user, const gchar * pass) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL) - || g_strrstr (user, ":") != NULL)) - return GST_RTSP_EINVAL; - - /* Make sure the username and passwd are being set for authentication */ - if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL)) - return GST_RTSP_EINVAL; - - /* ":" chars are not allowed in usernames for basic auth */ - if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL) - return GST_RTSP_EINVAL; - - g_free (conn->username); - g_free (conn->passwd); - - conn->auth_method = method; - conn->username = g_strdup (user); - conn->passwd = g_strdup (pass); - - return GST_RTSP_OK; -} - -/** - * str_case_hash: - * @key: ASCII string to hash - * - * Hashes @key in a case-insensitive manner. - * - * Returns: the hash code. - **/ -static guint -str_case_hash (gconstpointer key) -{ - const char *p = key; - guint h = g_ascii_toupper (*p); - - if (h) - for (p += 1; *p != '\0'; p++) - h = (h << 5) - h + g_ascii_toupper (*p); - - return h; -} - -/** - * str_case_equal: - * @v1: an ASCII string - * @v2: another ASCII string - * - * Compares @v1 and @v2 in a case-insensitive manner - * - * Returns: %TRUE if they are equal (modulo case) - **/ -static gboolean -str_case_equal (gconstpointer v1, gconstpointer v2) -{ - const char *string1 = v1; - const char *string2 = v2; - - return g_ascii_strcasecmp (string1, string2) == 0; -} - -/** - * gst_rtsp_connection_set_auth_param: - * @conn: a #GstRTSPConnection - * @param: authentication directive - * @value: value - * - * Setup @conn with authentication directives. This is not necesary for - * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For - * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge - * in the WWW-Authenticate response header and can include realm, domain, - * nonce, opaque, stale, algorithm, qop as per RFC2617. - * - * Since: 0.10.20 - */ -void -gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn, - const gchar * param, const gchar * value) -{ - g_return_if_fail (conn != NULL); - g_return_if_fail (param != NULL); - - if (conn->auth_params == NULL) { - conn->auth_params = - g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free); - } - g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value)); -} - -/** - * gst_rtsp_connection_clear_auth_params: - * @conn: a #GstRTSPConnection - * - * Clear the list of authentication directives stored in @conn. - * - * Since: 0.10.20 - */ -void -gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn) -{ - g_return_if_fail (conn != NULL); - - if (conn->auth_params != NULL) { - g_hash_table_destroy (conn->auth_params); - conn->auth_params = NULL; - } -} - -static GstRTSPResult -set_qos_dscp (gint fd, guint qos_dscp) -{ - union gst_sockaddr sa; - socklen_t slen = sizeof (sa); - gint af; - gint tos; - - if (fd == -1) - return GST_RTSP_OK; - - if (getsockname (fd, &sa.sa, &slen) < 0) - goto no_getsockname; - - af = sa.sa.sa_family; - - /* if this is an IPv4-mapped address then do IPv4 QoS */ - if (af == AF_INET6) { - if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr)) - af = AF_INET; - } - - /* extract and shift 6 bits of the DSCP */ - tos = (qos_dscp & 0x3f) << 2; - - switch (af) { - case AF_INET: - if (SETSOCKOPT (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0) - goto no_setsockopt; - break; - case AF_INET6: -#ifdef IPV6_TCLASS - if (SETSOCKOPT (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0) - goto no_setsockopt; - break; -#endif - default: - goto wrong_family; - } - - return GST_RTSP_OK; - - /* ERRORS */ -no_getsockname: -no_setsockopt: - { - return GST_RTSP_ESYS; - } - -wrong_family: - { - return GST_RTSP_ERROR; - } -} - -/** - * gst_rtsp_connection_set_qos_dscp: - * @conn: a #GstRTSPConnection - * @qos_dscp: DSCP value - * - * Configure @conn to use the specified DSCP value. - * - * Returns: #GST_RTSP_OK on success. - * - * Since: 0.10.20 - */ -GstRTSPResult -gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp) -{ - GstRTSPResult res; - - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL); - - res = set_qos_dscp (conn->fd0.fd, qos_dscp); - if (res == GST_RTSP_OK) - res = set_qos_dscp (conn->fd1.fd, qos_dscp); - - return res; -} - - -/** - * gst_rtsp_connection_get_url: - * @conn: a #GstRTSPConnection - * - * Retrieve the URL of the other end of @conn. - * - * Returns: The URL. This value remains valid until the - * connection is freed. - * - * Since: 0.10.23 - */ -GstRTSPUrl * -gst_rtsp_connection_get_url (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, NULL); - - return conn->url; -} - -/** - * gst_rtsp_connection_get_ip: - * @conn: a #GstRTSPConnection - * - * Retrieve the IP address of the other end of @conn. - * - * Returns: The IP address as a string. this value remains valid until the - * connection is closed. - * - * Since: 0.10.20 - */ -const gchar * -gst_rtsp_connection_get_ip (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, NULL); - - return conn->ip; -} - -/** - * gst_rtsp_connection_set_ip: - * @conn: a #GstRTSPConnection - * @ip: an ip address - * - * Set the IP address of the server. - * - * Since: 0.10.23 - */ -void -gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip) -{ - g_return_if_fail (conn != NULL); - - g_free (conn->ip); - conn->ip = g_strdup (ip); -} - -/** - * gst_rtsp_connection_get_readfd: - * @conn: a #GstRTSPConnection - * - * Get the file descriptor for reading. - * - * Returns: the file descriptor used for reading or -1 on error. The file - * descriptor remains valid until the connection is closed. - * - * Since: 0.10.23 - */ -gint -gst_rtsp_connection_get_readfd (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, -1); - g_return_val_if_fail (conn->readfd != NULL, -1); - - return conn->readfd->fd; -} - -/** - * gst_rtsp_connection_get_writefd: - * @conn: a #GstRTSPConnection - * - * Get the file descriptor for writing. - * - * Returns: the file descriptor used for writing or -1 on error. The file - * descriptor remains valid until the connection is closed. - * - * Since: 0.10.23 - */ -gint -gst_rtsp_connection_get_writefd (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, -1); - g_return_val_if_fail (conn->writefd != NULL, -1); - - return conn->writefd->fd; -} - -/** - * gst_rtsp_connection_set_http_mode: - * @conn: a #GstRTSPConnection - * @enable: %TRUE to enable manual HTTP mode - * - * By setting the HTTP mode to %TRUE the message parsing will support HTTP - * messages in addition to the RTSP messages. It will also disable the - * automatic handling of setting up an HTTP tunnel. - * - * Since: 0.10.25 - */ -void -gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable) -{ - g_return_if_fail (conn != NULL); - - conn->manual_http = enable; -} - -/** - * gst_rtsp_connection_set_tunneled: - * @conn: a #GstRTSPConnection - * @tunneled: the new state - * - * Set the HTTP tunneling state of the connection. This must be configured before - * the @conn is connected. - * - * Since: 0.10.23 - */ -void -gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled) -{ - g_return_if_fail (conn != NULL); - g_return_if_fail (conn->readfd == NULL); - g_return_if_fail (conn->writefd == NULL); - - conn->tunneled = tunneled; -} - -/** - * gst_rtsp_connection_is_tunneled: - * @conn: a #GstRTSPConnection - * - * Get the tunneling state of the connection. - * - * Returns: if @conn is using HTTP tunneling. - * - * Since: 0.10.23 - */ -gboolean -gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, FALSE); - - return conn->tunneled; -} - -/** - * gst_rtsp_connection_get_tunnelid: - * @conn: a #GstRTSPConnection - * - * Get the tunnel session id the connection. - * - * Returns: returns a non-empty string if @conn is being tunneled over HTTP. - * - * Since: 0.10.23 - */ -const gchar * -gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn) -{ - g_return_val_if_fail (conn != NULL, NULL); - - if (!conn->tunneled) - return NULL; - - return conn->tunnelid; -} - -/** - * gst_rtsp_connection_do_tunnel: - * @conn: a #GstRTSPConnection - * @conn2: a #GstRTSPConnection or %NULL - * - * If @conn received the first tunnel connection and @conn2 received - * the second tunnel connection, link the two connections together so that - * @conn manages the tunneled connection. - * - * After this call, @conn2 cannot be used anymore and must be freed with - * gst_rtsp_connection_free(). - * - * If @conn2 is %NULL then only the base64 decoding context will be setup for - * @conn. - * - * Returns: return GST_RTSP_OK on success. - * - * Since: 0.10.23 - */ -GstRTSPResult -gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn, - GstRTSPConnection * conn2) -{ - g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); - - if (conn2 != NULL) { - g_return_val_if_fail (conn->tstate == TUNNEL_STATE_GET, GST_RTSP_EINVAL); - g_return_val_if_fail (conn2->tstate == TUNNEL_STATE_POST, GST_RTSP_EINVAL); - g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid, - TUNNELID_LEN), GST_RTSP_EINVAL); - - /* both connections have fd0 as the read/write socket. start by taking the - * socket from conn2 and set it as the socket in conn */ - conn->fd1 = conn2->fd0; - - /* clean up some of the state of conn2 */ - gst_poll_remove_fd (conn2->fdset, &conn2->fd0); - conn2->fd0.fd = -1; - conn2->readfd = conn2->writefd = NULL; - - /* We make fd0 the write socket and fd1 the read socket. */ - conn->writefd = &conn->fd0; - conn->readfd = &conn->fd1; - - conn->tstate = TUNNEL_STATE_COMPLETE; - } - - /* we need base64 decoding for the readfd */ - conn->ctx.state = 0; - conn->ctx.save = 0; - conn->ctx.cout = 0; - conn->ctx.coutl = 0; - conn->ctxp = &conn->ctx; - - return GST_RTSP_OK; -} - -#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define WRITE_COND (G_IO_OUT | G_IO_ERR) - -typedef struct -{ - guint8 *data; - guint size; - guint id; -} GstRTSPRec; - -/* async functions */ -struct _GstRTSPWatch -{ - GSource source; - - GstRTSPConnection *conn; - - GstRTSPBuilder builder; - GstRTSPMessage message; - - GPollFD readfd; - GPollFD writefd; - gboolean write_added; - - /* queued message for transmission */ - guint id; - GMutex *mutex; - GQueue *messages; - guint8 *write_data; - guint write_off; - guint write_size; - guint write_id; - - GstRTSPWatchFuncs funcs; - - gpointer user_data; - GDestroyNotify notify; -}; - -static gboolean -gst_rtsp_source_prepare (GSource * source, gint * timeout) -{ - GstRTSPWatch *watch = (GstRTSPWatch *) source; - - if (watch->conn->initial_buffer != NULL) - return TRUE; - - *timeout = (watch->conn->timeout * 1000); - - return FALSE; -} - -static gboolean -gst_rtsp_source_check (GSource * source) -{ - GstRTSPWatch *watch = (GstRTSPWatch *) source; - - if (watch->readfd.revents & READ_COND) - return TRUE; - - if (watch->writefd.revents & WRITE_COND) - return TRUE; - - return FALSE; -} - -static gboolean -gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED, - gpointer user_data G_GNUC_UNUSED) -{ - GstRTSPWatch *watch = (GstRTSPWatch *) source; - GstRTSPResult res; - - /* first read as much as we can */ - if (watch->readfd.revents & READ_COND || watch->conn->initial_buffer != NULL) { - do { - res = build_next (&watch->builder, &watch->message, watch->conn); - if (res == GST_RTSP_EINTR) - break; - else if (G_UNLIKELY (res == GST_RTSP_EEOF)) - goto eof; - else if (G_LIKELY (res == GST_RTSP_OK)) { - if (!watch->conn->manual_http && - watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) { - if (watch->conn->tstate == TUNNEL_STATE_NONE && - watch->message.type_data.request.method == GST_RTSP_GET) { - GstRTSPMessage *response; - GstRTSPStatusCode code; - - watch->conn->tstate = TUNNEL_STATE_GET; - - if (watch->funcs.tunnel_start) - code = watch->funcs.tunnel_start (watch, watch->user_data); - else - code = GST_RTSP_STS_OK; - - /* queue the response */ - response = gen_tunnel_reply (watch->conn, code, &watch->message); - gst_rtsp_watch_send_message (watch, response, NULL); - gst_rtsp_message_free (response); - goto read_done; - } else if (watch->conn->tstate == TUNNEL_STATE_NONE && - watch->message.type_data.request.method == GST_RTSP_POST) { - watch->conn->tstate = TUNNEL_STATE_POST; - - /* in the callback the connection should be tunneled with the - * GET connection */ - if (watch->funcs.tunnel_complete) - watch->funcs.tunnel_complete (watch, watch->user_data); - goto read_done; - } - } - } - - if (!watch->conn->manual_http) { - /* if manual HTTP support is not enabled, then restore the message to - * what it would have looked like without the support for parsing HTTP - * messages being present */ - if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) { - watch->message.type = GST_RTSP_MESSAGE_REQUEST; - watch->message.type_data.request.method = GST_RTSP_INVALID; - if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0) - watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID; - res = GST_RTSP_EPARSE; - } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) { - watch->message.type = GST_RTSP_MESSAGE_RESPONSE; - if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0) - watch->message.type_data.response.version = - GST_RTSP_VERSION_INVALID; - res = GST_RTSP_EPARSE; - } - } - - if (G_LIKELY (res == GST_RTSP_OK)) { - if (watch->funcs.message_received) - watch->funcs.message_received (watch, &watch->message, - watch->user_data); - } else { - if (watch->funcs.error_full) - GST_RTSP_CHECK (watch->funcs.error_full (watch, res, &watch->message, - 0, watch->user_data), error); - else - goto error; - } - - read_done: - gst_rtsp_message_unset (&watch->message); - build_reset (&watch->builder); - } while (FALSE); - } - - if (watch->writefd.revents & WRITE_COND) { - g_mutex_lock (watch->mutex); - do { - if (watch->write_data == NULL) { - GstRTSPRec *rec; - - /* get a new message from the queue */ - rec = g_queue_pop_tail (watch->messages); - if (rec == NULL) - goto done; - - watch->write_off = 0; - watch->write_data = rec->data; - watch->write_size = rec->size; - watch->write_id = rec->id; - - g_slice_free (GstRTSPRec, rec); - } - - res = write_bytes (watch->writefd.fd, watch->write_data, - &watch->write_off, watch->write_size); - g_mutex_unlock (watch->mutex); - if (res == GST_RTSP_EINTR) - goto write_blocked; - else if (G_LIKELY (res == GST_RTSP_OK)) { - if (watch->funcs.message_sent) - watch->funcs.message_sent (watch, watch->write_id, watch->user_data); - } else { - if (watch->funcs.error_full) - GST_RTSP_CHECK (watch->funcs.error_full (watch, res, NULL, - watch->write_id, watch->user_data), error); - else - goto error; - } - g_mutex_lock (watch->mutex); - - g_free (watch->write_data); - watch->write_data = NULL; - } while (TRUE); - - done: - if (watch->write_added) { - g_source_remove_poll ((GSource *) watch, &watch->writefd); - watch->write_added = FALSE; - watch->writefd.revents = 0; - } - - g_mutex_unlock (watch->mutex); - } - -write_blocked: - return TRUE; - - /* ERRORS */ -eof: - { - if (watch->funcs.closed) - watch->funcs.closed (watch, watch->user_data); - return FALSE; - } -error: - { - if (watch->funcs.error) - watch->funcs.error (watch, res, watch->user_data); - return FALSE; - } -} - -static void -gst_rtsp_rec_free (gpointer data) -{ - GstRTSPRec *rec = data; - - g_free (rec->data); - g_slice_free (GstRTSPRec, rec); -} - -static void -gst_rtsp_source_finalize (GSource * source) -{ - GstRTSPWatch *watch = (GstRTSPWatch *) source; - - build_reset (&watch->builder); - gst_rtsp_message_unset (&watch->message); - - g_queue_foreach (watch->messages, (GFunc) gst_rtsp_rec_free, NULL); - g_queue_free (watch->messages); - watch->messages = NULL; - - g_mutex_free (watch->mutex); - - g_free (watch->write_data); - - if (watch->notify) - watch->notify (watch->user_data); -} - -static GSourceFuncs gst_rtsp_source_funcs = { - gst_rtsp_source_prepare, - gst_rtsp_source_check, - gst_rtsp_source_dispatch, - gst_rtsp_source_finalize, - NULL, - NULL -}; - -/** - * gst_rtsp_watch_new: - * @conn: a #GstRTSPConnection - * @funcs: watch functions - * @user_data: user data to pass to @funcs - * @notify: notify when @user_data is not referenced anymore - * - * Create a watch object for @conn. The functions provided in @funcs will be - * called with @user_data when activity happened on the watch. - * - * The new watch is usually created so that it can be attached to a - * maincontext with gst_rtsp_watch_attach(). - * - * @conn must exist for the entire lifetime of the watch. - * - * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP - * communication. Free with gst_rtsp_watch_unref () after usage. - * - * Since: 0.10.23 - */ -GstRTSPWatch * -gst_rtsp_watch_new (GstRTSPConnection * conn, - GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify) -{ - GstRTSPWatch *result; - - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (funcs != NULL, NULL); - g_return_val_if_fail (conn->readfd != NULL, NULL); - g_return_val_if_fail (conn->writefd != NULL, NULL); - - result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs, - sizeof (GstRTSPWatch)); - - result->conn = conn; - result->builder.state = STATE_START; - - result->mutex = g_mutex_new (); - result->messages = g_queue_new (); - - result->readfd.fd = -1; - result->writefd.fd = -1; - - gst_rtsp_watch_reset (result); - - result->funcs = *funcs; - result->user_data = user_data; - result->notify = notify; - - /* only add the read fd, the write fd is only added when we have data - * to send. */ - g_source_add_poll ((GSource *) result, &result->readfd); - - return result; -} - -/** - * gst_rtsp_watch_reset: - * @watch: a #GstRTSPWatch - * - * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel() - * when the file descriptors of the connection might have changed. - * - * Since: 0.10.23 - */ -void -gst_rtsp_watch_reset (GstRTSPWatch * watch) -{ - if (watch->readfd.fd != -1) - g_source_remove_poll ((GSource *) watch, &watch->readfd); - if (watch->writefd.fd != -1) - g_source_remove_poll ((GSource *) watch, &watch->writefd); - - watch->readfd.fd = watch->conn->readfd->fd; - watch->readfd.events = READ_COND; - watch->readfd.revents = 0; - - watch->writefd.fd = watch->conn->writefd->fd; - watch->writefd.events = WRITE_COND; - watch->writefd.revents = 0; - watch->write_added = FALSE; - - g_source_add_poll ((GSource *) watch, &watch->readfd); -} - -/** - * gst_rtsp_watch_attach: - * @watch: a #GstRTSPWatch - * @context: a GMainContext (if NULL, the default context will be used) - * - * Adds a #GstRTSPWatch to a context so that it will be executed within that context. - * - * Returns: the ID (greater than 0) for the watch within the GMainContext. - * - * Since: 0.10.23 - */ -guint -gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context) -{ - g_return_val_if_fail (watch != NULL, 0); - - return g_source_attach ((GSource *) watch, context); -} - -/** - * gst_rtsp_watch_unref: - * @watch: a #GstRTSPWatch - * - * Decreases the reference count of @watch by one. If the resulting reference - * count is zero the watch and associated memory will be destroyed. - * - * Since: 0.10.23 - */ -void -gst_rtsp_watch_unref (GstRTSPWatch * watch) -{ - g_return_if_fail (watch != NULL); - - g_source_unref ((GSource *) watch); -} - -/** - * gst_rtsp_watch_write_data: - * @watch: a #GstRTSPWatch - * @data: the data to queue - * @size: the size of @data - * @id: location for a message ID or %NULL - * - * Write @data using the connection of the @watch. If it cannot be sent - * immediately, it will be queued for transmission in @watch. The contents of - * @message will then be serialized and transmitted when the connection of the - * @watch becomes writable. In case the @message is queued, the ID returned in - * @id will be non-zero and used as the ID argument in the message_sent - * callback. - * - * This function will take ownership of @data and g_free() it after use. - * - * Returns: #GST_RTSP_OK on success. - * - * Since: 0.10.25 - */ -GstRTSPResult -gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data, - guint size, guint * id) -{ - GstRTSPResult res; - GstRTSPRec *rec; - guint off = 0; - - g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (size != 0, GST_RTSP_EINVAL); - - g_mutex_lock (watch->mutex); - - if (watch->messages->length == 0) { - res = write_bytes (watch->writefd.fd, data, &off, size); - if (res != GST_RTSP_EINTR) { - if (id != NULL) - *id = 0; - g_free ((gpointer) data); - goto done; - } - } - - /* make a record with the data and id */ - rec = g_slice_new (GstRTSPRec); - if (off == 0) { - rec->data = (guint8 *) data; - rec->size = size; - } else { - rec->data = g_memdup (data + off, size - off); - rec->size = size - off; - g_free ((gpointer) data); - } - - do { - /* make sure rec->id is never 0 */ - rec->id = ++watch->id; - } while (G_UNLIKELY (rec->id == 0)); - - /* add the record to a queue. FIXME we would like to have an upper limit here */ - g_queue_push_head (watch->messages, rec); - - /* make sure the main context will now also check for writability on the - * socket */ - if (!watch->write_added) { - g_source_add_poll ((GSource *) watch, &watch->writefd); - watch->write_added = TRUE; - } - - if (id != NULL) - *id = rec->id; - res = GST_RTSP_OK; - -done: - g_mutex_unlock (watch->mutex); - return res; -} - -/** - * gst_rtsp_watch_send_message: - * @watch: a #GstRTSPWatch - * @message: a #GstRTSPMessage - * @id: location for a message ID or %NULL - * - * Send a @message using the connection of the @watch. If it cannot be sent - * immediately, it will be queued for transmission in @watch. The contents of - * @message will then be serialized and transmitted when the connection of the - * @watch becomes writable. In case the @message is queued, the ID returned in - * @id will be non-zero and used as the ID argument in the message_sent - * callback. - * - * Returns: #GST_RTSP_OK on success. - * - * Since: 0.10.25 - */ -GstRTSPResult -gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message, - guint * id) -{ - GString *str; - guint size; - - g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); - - /* make a record with the message as a string and id */ - str = message_to_string (watch->conn, message); - size = str->len; - return gst_rtsp_watch_write_data (watch, - (guint8 *) g_string_free (str, FALSE), size, id); -} - -/** - * gst_rtsp_watch_queue_data: - * @watch: a #GstRTSPWatch - * @data: the data to queue - * @size: the size of @data - * - * Queue @data for transmission in @watch. It will be transmitted when the - * connection of the @watch becomes writable. - * - * This function will take ownership of @data and g_free() it after use. - * - * The return value of this function will be used as the id argument in the - * message_sent callback. - * - * Deprecated: Use gst_rtsp_watch_write_data() - * - * Returns: an id. - * - * Since: 0.10.24 - */ -#ifndef GST_REMOVE_DEPRECATED -guint -gst_rtsp_watch_queue_data (GstRTSPWatch * watch, const guint8 * data, - guint size) -{ - GstRTSPRec *rec; - - g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (size != 0, GST_RTSP_EINVAL); - - g_mutex_lock (watch->mutex); - - /* make a record with the data and id */ - rec = g_slice_new (GstRTSPRec); - rec->data = (guint8 *) data; - rec->size = size; - do { - /* make sure rec->id is never 0 */ - rec->id = ++watch->id; - } while (G_UNLIKELY (rec->id == 0)); - - /* add the record to a queue. FIXME we would like to have an upper limit here */ - g_queue_push_head (watch->messages, rec); - - /* make sure the main context will now also check for writability on the - * socket */ - if (!watch->write_added) { - g_source_add_poll ((GSource *) watch, &watch->writefd); - watch->write_added = TRUE; - } - - g_mutex_unlock (watch->mutex); - return rec->id; -} -#endif /* GST_REMOVE_DEPRECATED */ - -/** - * gst_rtsp_watch_queue_message: - * @watch: a #GstRTSPWatch - * @message: a #GstRTSPMessage - * - * Queue a @message for transmission in @watch. The contents of this - * message will be serialized and transmitted when the connection of the - * @watch becomes writable. - * - * The return value of this function will be used as the id argument in the - * message_sent callback. - * - * Deprecated: Use gst_rtsp_watch_send_message() - * - * Returns: an id. - * - * Since: 0.10.23 - */ -#ifndef GST_REMOVE_DEPRECATED -guint -gst_rtsp_watch_queue_message (GstRTSPWatch * watch, GstRTSPMessage * message) -{ - GString *str; - guint size; - - g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL); - g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); - - /* make a record with the message as a string and id */ - str = message_to_string (watch->conn, message); - size = str->len; - return gst_rtsp_watch_queue_data (watch, - (guint8 *) g_string_free (str, FALSE), size); -} -#endif /* GST_REMOVE_DEPRECATED */ diff --git a/gst-libs/gst/rtsp/rtsp-marshal.c b/gst-libs/gst/rtsp/rtsp-marshal.c deleted file mode 100644 index dfa2c50..0000000 --- a/gst-libs/gst/rtsp/rtsp-marshal.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "rtsp-marshal.h" - -#include - - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */ -void -gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure * closure, - GValue * return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue * param_values, - gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) -{ - typedef gint (*GMarshalFunc_ENUM__POINTER_POINTER) (gpointer data1, - gpointer arg_1, gpointer arg_2, gpointer data2); - register GMarshalFunc_ENUM__POINTER_POINTER callback; - register GCClosure *cc = (GCClosure *) closure; - register gpointer data1, data2; - gint v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } else { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = - (GMarshalFunc_ENUM__POINTER_POINTER) (marshal_data ? marshal_data : - cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), data2); - - g_value_set_enum (return_value, v_return); -} diff --git a/gst-libs/gst/rtsp/rtsp-marshal.h b/gst-libs/gst/rtsp/rtsp-marshal.h deleted file mode 100644 index 0106232..0000000 --- a/gst-libs/gst/rtsp/rtsp-marshal.h +++ /dev/null @@ -1,20 +0,0 @@ - -#ifndef __gst_rtsp_marshal_MARSHAL_H__ -#define __gst_rtsp_marshal_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */ -extern void gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); - -G_END_DECLS - -#endif /* __gst_rtsp_marshal_MARSHAL_H__ */ - diff --git a/gst-libs/gst/rtsp/rtspdefs.patch b/gst-libs/gst/rtsp/rtspdefs.patch deleted file mode 100644 index bc16338..0000000 --- a/gst-libs/gst/rtsp/rtspdefs.patch +++ /dev/null @@ -1,73 +0,0 @@ -commit bf5ef87699b8ef602548eec131312d7a733e278e -Author: Josep Torra -Date: Tue Apr 14 18:03:09 2009 +0200 - - Added RTSP headers related to Windows Media extension. - -diff --git a/gst-libs/gst/rtsp/gstrtspdefs.c b/gst-libs/gst/rtsp/gstrtspdefs.c -index 0ab2b95..8b086e5 100644 ---- a/gst-libs/gst/rtsp/gstrtspdefs.c -+++ b/gst-libs/gst/rtsp/gstrtspdefs.c -@@ -164,6 +164,27 @@ static const gchar *rtsp_headers[] = { - "ETag", /* ETag */ - "If-Match", /* If-Match */ - -+ /* WM extensions [MS-RTSP] */ -+ "Accept-Charset", /* Accept-Charset */ -+ "Supported", /* Supported */ -+ "Vary", /* Vary */ -+ "X-Accelerate-Streaming", /* X-Accelerate-Streaming */ -+ "X-Accept-Authentication", /* X-Accept-Authentication */ -+ "X-Accept-Proxy-Authentication", /* X-Accept-Proxy-Authentication */ -+ "X-Broadcast-Id", /* X-Broadcast-Id */ -+ "X-Burst-Streaming", /* X-Burst-Streaming */ -+ "X-Notice", /* X-Notice */ -+ "X-Player-Lag-Time", /* X-Player-Lag-Time */ -+ "X-Playlist", /* X-Playlist */ -+ "X-Playlist-Change-Notice", /* X-Playlist-Change-Notice */ -+ "X-Playlist-Gen-Id", /* X-Playlist-Gen-Id */ -+ "X-Playlist-Seek-Id", /* X-Playlist-Seek-Id */ -+ "X-Proxy-Client-Agent", /* X-Proxy-Client-Agent */ -+ "X-Proxy-Client-Verb", /* X-Proxy-Client-Verb */ -+ "X-Receding-PlaylistChange", /* X-Receding-PlaylistChange */ -+ "X-RTP-Info", /* X-RTP-Info */ -+ "X-StartupProfile", /* X-StartupProfile */ -+ - NULL - }; - -diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h -index dd4b531..ae3b105 100644 ---- a/gst-libs/gst/rtsp/gstrtspdefs.h -+++ b/gst-libs/gst/rtsp/gstrtspdefs.h -@@ -287,7 +287,29 @@ typedef enum { - - /* Since 0.10.23 */ - GST_RTSP_HDR_ETAG, /* ETag */ -- GST_RTSP_HDR_IF_MATCH /* If-Match */ -+ GST_RTSP_HDR_IF_MATCH, /* If-Match */ -+ -+ /* WM extensions [MS-RTSP] */ -+ GST_RTSP_HDR_ACCEPT_CHARSET, /* Accept-Charset */ -+ GST_RTSP_HDR_SUPPORTED, /* Supported */ -+ GST_RTSP_HDR_VARY, /* Vary */ -+ GST_RTSP_HDR_X_ACCELERATE_STREAMING, /* X-Accelerate-Streaming */ -+ GST_RTSP_HDR_X_ACCEPT_AUTHENT, /* X-Accept-Authentication */ -+ GST_RTSP_HDR_X_ACCEPT_PROXY_AUTHENT, /* X-Accept-Proxy-Authentication */ -+ GST_RTSP_HDR_X_BROADCAST_ID, /* X-Broadcast-Id */ -+ GST_RTSP_HDR_X_BURST_STREAMING, /* X-Burst-Streaming */ -+ GST_RTSP_HDR_X_NOTICE, /* X-Notice */ -+ GST_RTSP_HDR_X_PLAYER_LAG_TIME, /* X-Player-Lag-Time */ -+ GST_RTSP_HDR_X_PLAYLIST, /* X-Playlist */ -+ GST_RTSP_HDR_X_PLAYLIST_CHANGE_NOTICE, /* X-Playlist-Change-Notice */ -+ GST_RTSP_HDR_X_PLAYLIST_GEN_ID, /* X-Playlist-Gen-Id */ -+ GST_RTSP_HDR_X_PLAYLIST_SEEK_ID, /* X-Playlist-Seek-Id */ -+ GST_RTSP_HDR_X_PROXY_CLIENT_AGENT, /* X-Proxy-Client-Agent */ -+ GST_RTSP_HDR_X_PROXY_CLIENT_VERB, /* X-Proxy-Client-Verb */ -+ GST_RTSP_HDR_X_RECEDING_PLAYLISTCHANGE, /* X-Receding-PlaylistChange */ -+ GST_RTSP_HDR_X_RTP_INFO, /* X-RTP-Info */ -+ GST_RTSP_HDR_X_STARTUPPROFILE /* X-StartupProfile */ -+ - } GstRTSPHeaderField; - - typedef enum { diff --git a/gst/videorate/videorate-discont.patch b/gst/videorate/videorate-discont.patch deleted file mode 100644 index baca0d5..0000000 --- a/gst/videorate/videorate-discont.patch +++ /dev/null @@ -1,48 +0,0 @@ -diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c -index 8d22186..7afcfdd 100644 ---- a/gst/videorate/gstvideorate.c -+++ b/gst/videorate/gstvideorate.c -@@ -357,6 +357,7 @@ gst_video_rate_reset (GstVideoRate * videorate) - videorate->drop = 0; - videorate->dup = 0; - videorate->next_ts = GST_CLOCK_TIME_NONE; -+ videorate->discont = TRUE; - gst_video_rate_swap_prev (videorate, NULL, 0); - - gst_segment_init (&videorate->segment, GST_FORMAT_TIME); -@@ -409,6 +410,13 @@ gst_video_rate_flush_prev (GstVideoRate * videorate) - GST_BUFFER_OFFSET (outbuf) = videorate->out; - GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1; - -+ if (videorate->discont) { -+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); -+ videorate->discont = FALSE; -+ } -+ else -+ GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT); -+ - /* this is the timestamp we put on the buffer */ - push_ts = videorate->next_ts; - -@@ -810,6 +818,9 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition) - videorate = GST_VIDEO_RATE (element); - - switch (transition) { -+ case GST_STATE_CHANGE_READY_TO_PAUSED: -+ videorate->discont = TRUE; -+ break; - default: - break; - } -diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h -index ea6063b..fe7feb6 100644 ---- a/gst/videorate/gstvideorate.h -+++ b/gst/videorate/gstvideorate.h -@@ -56,6 +56,7 @@ struct _GstVideoRate - GstBuffer *prevbuf; - guint64 prev_ts; /* Previous buffer timestamp */ - guint64 segment_out; /* in-segment counting */ -+ gboolean discont; - - /* segment handling */ - GstSegment segment; -- 2.7.4