diff -urN gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.c gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.c --- gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.c 1969-12-31 19:00:00.000000000 -0500 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.c 2005-03-02 11:08:24.546323513 -0500 @@ -0,0 +1,655 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2004> Thomas Vander Stichele + * + * 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. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "gsttcp.h" +#include "gsthttpclientsrc.h" +#include /* memset */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_FIONREAD_IN_SYS_FILIO +#include +#endif + +GST_DEBUG_CATEGORY (httpclientsrc_debug); +#define GST_CAT_DEFAULT httpclientsrc_debug + +#define MAX_READ_SIZE 4 * 1024 + +/* elementfactory information */ +static GstElementDetails gst_httpclientsrc_details = +GST_ELEMENT_DETAILS ("HTTP Client source", + "Source/Network", + "Receive data as a client over the network via HTTP", + "Jamey Hicks based on tcpclientsrc by Thomas Vander Stichele "); + +/* HttpclientSrc signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_LOCATION, + ARG_METHOD, + ARG_PROTOCOL +}; + +#define HTTP_DEFAULT_METHOD "GET" + +static void gst_httpclientsrc_base_init (gpointer g_class); +static void gst_httpclientsrc_class_init (GstHttpclientSrc * klass); +static void gst_httpclientsrc_init (GstHttpclientSrc * httpclientsrc); + +static GstCaps *gst_httpclientsrc_getcaps (GstPad * pad); + +static GstData *gst_httpclientsrc_get (GstPad * pad); +static GstElementStateReturn gst_httpclientsrc_change_state (GstElement * + element); + +static void gst_httpclientsrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_httpclientsrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_httpclientsrc_set_clock (GstElement * element, GstClock * clock); + +static GstElementClass *parent_class = NULL; + +/*static guint gst_httpclientsrc_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_httpclientsrc_get_type (void) +{ + static GType httpclientsrc_type = 0; + + + if (!httpclientsrc_type) { + static const GTypeInfo httpclientsrc_info = { + sizeof (GstHttpclientSrcClass), + gst_httpclientsrc_base_init, + NULL, + (GClassInitFunc) gst_httpclientsrc_class_init, + NULL, + NULL, + sizeof (GstHttpclientSrc), + 0, + (GInstanceInitFunc) gst_httpclientsrc_init, + NULL + }; + + httpclientsrc_type = + g_type_register_static (GST_TYPE_ELEMENT, "GstHttpclientSrc", + &httpclientsrc_info, 0); + } + return httpclientsrc_type; +} + +static void +gst_httpclientsrc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &gst_httpclientsrc_details); +} + +static void +gst_httpclientsrc_class_init (GstHttpclientSrc * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION, + g_param_spec_string ("location", "Source Location (URL)", + "URL of the data to read", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD, + g_param_spec_string ("method", "HTTP METHOD, defaults to GET", + "Method of the read request", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_PROTOCOL, + g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in", + GST_TYPE_TCP_PROTOCOL_TYPE, GST_TCP_PROTOCOL_TYPE_NONE, + G_PARAM_READWRITE)); + + gobject_class->set_property = gst_httpclientsrc_set_property; + gobject_class->get_property = gst_httpclientsrc_get_property; + + gstelement_class->change_state = gst_httpclientsrc_change_state; + gstelement_class->set_clock = gst_httpclientsrc_set_clock; + + GST_DEBUG_CATEGORY_INIT (httpclientsrc_debug, "httpclientsrc", 0, + "HTTP Client Source"); +} + +static void +gst_httpclientsrc_set_clock (GstElement * element, GstClock * clock) +{ + GstHttpclientSrc *httpclientsrc; + + httpclientsrc = GST_HTTPCLIENTSRC (element); + + httpclientsrc->clock = clock; +} + +static void +gst_httpclientsrc_init (GstHttpclientSrc * this) +{ + /* create the src pad */ + this->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (this), this->srcpad); + gst_pad_set_get_function (this->srcpad, gst_httpclientsrc_get); + gst_pad_set_getcaps_function (this->srcpad, gst_httpclientsrc_getcaps); + + this->port = TCP_DEFAULT_PORT; + this->method = g_strdup(HTTP_DEFAULT_METHOD); + this->location = NULL; + this->host = NULL; + this->clock = NULL; + this->sock_fd = -1; + this->protocol = GST_TCP_PROTOCOL_TYPE_NONE; + this->curoffset = 0; + this->caps = NULL; + + GST_FLAG_UNSET (this, GST_HTTPCLIENTSRC_OPEN); +} + +static GstCaps * +gst_httpclientsrc_getcaps (GstPad * pad) +{ + GstHttpclientSrc *src; + GstCaps *caps = NULL; + + src = GST_HTTPCLIENTSRC (GST_OBJECT_PARENT (pad)); + + if (!GST_FLAG_IS_SET (src, GST_HTTPCLIENTSRC_OPEN)) + caps = gst_caps_new_any (); + else if (src->caps) + caps = gst_caps_copy (src->caps); + else + caps = gst_caps_new_any (); + GST_DEBUG_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps); + g_assert (GST_IS_CAPS (caps)); + return caps; +} + +static GstData * +gst_httpclientsrc_get (GstPad * pad) +{ + GstHttpclientSrc *src; + size_t readsize; + int ret; + + GstData *data = NULL; + GstBuffer *buf = NULL; + + g_return_val_if_fail (pad != NULL, NULL); + g_return_val_if_fail (GST_IS_PAD (pad), NULL); + src = GST_HTTPCLIENTSRC (GST_OBJECT_PARENT (pad)); + g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_HTTPCLIENTSRC_OPEN), NULL); + + /* try to negotiate here */ + if (!gst_pad_is_negotiated (pad)) { + if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pad))) { + GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), GST_ERROR_SYSTEM); + gst_buffer_unref (buf); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + } + + /* if we have a left over buffer after a discont, return that */ + if (src->buffer_after_discont) { + buf = src->buffer_after_discont; + GST_LOG_OBJECT (src, + "Returning buffer after discont of size %d, ts %" + GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT + ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT, + GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), + GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); + src->buffer_after_discont = NULL; + return GST_DATA (buf); + } + + /* read the buffer header if we're using a protocol */ + switch (src->protocol) { + fd_set testfds; + + case GST_TCP_PROTOCOL_TYPE_NONE: + /* do a blocking select on the socket */ + FD_ZERO (&testfds); + FD_SET (src->sock_fd, &testfds); + ret = select (src->sock_fd + 1, &testfds, (fd_set *) 0, (fd_set *) 0, 0); + /* no action (0) is an error too in our case */ + if (ret <= 0) { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("select failed: %s", g_strerror (errno))); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + + /* ask how much is available for reading on the socket */ + ret = ioctl (src->sock_fd, FIONREAD, &readsize); + if (ret < 0) { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("ioctl failed: %s", g_strerror (errno))); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + GST_LOG_OBJECT (src, "ioctl says %d bytes available", readsize); + buf = gst_buffer_new_and_alloc (readsize); + break; + case GST_TCP_PROTOCOL_TYPE_GDP: + if (!(data = gst_tcp_gdp_read_header (GST_ELEMENT (src), src->sock_fd))) { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("Could not read data header through GDP")); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + if (GST_IS_EVENT (data)) + return data; + buf = GST_BUFFER (data); + + GST_LOG_OBJECT (src, "Going to read data from socket into buffer %p", + buf); + /* use this new buffer to read data into */ + readsize = GST_BUFFER_SIZE (buf); + break; + default: + g_warning ("Unhandled protocol type"); + break; + } + + GST_LOG_OBJECT (src, "Reading %d bytes", readsize); + ret = gst_tcp_socket_read (src->sock_fd, GST_BUFFER_DATA (buf), readsize); + if (ret < 0) { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + gst_buffer_unref (buf); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + + /* if we read 0 bytes, and we're blocking, we hit eos */ + if (ret == 0) { + GST_DEBUG ("blocking read returns 0, EOS"); + gst_buffer_unref (buf); + gst_element_set_eos (GST_ELEMENT (src)); + return GST_DATA (gst_event_new (GST_EVENT_EOS)); + } + + readsize = ret; + GST_BUFFER_SIZE (buf) = readsize; + GST_BUFFER_MAXSIZE (buf) = readsize; + + /* FIXME: we could decide to set OFFSET and OFFSET_END for non-protocol + * streams to mean the bytes processed */ + + /* if this is our first buffer, we need to send a discont with the + * given timestamp or the current offset, and store the buffer for + * the next iteration through the get loop */ + if (src->send_discont) { + GstClockTime timestamp; + GstEvent *event; + + src->send_discont = FALSE; + src->buffer_after_discont = buf; + /* if the timestamp is valid, send a timed discont + * taking into account the incoming buffer's timestamps */ + timestamp = GST_BUFFER_TIMESTAMP (buf); + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + GST_DEBUG_OBJECT (src, + "sending discontinuous with timestamp %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp)); + event = + gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, timestamp, NULL); + return GST_DATA (event); + } + /* otherwise, send an offset discont */ + GST_DEBUG_OBJECT (src, "sending discontinuous with offset %d", + src->curoffset); + event = + gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, + NULL); + return GST_DATA (event); + } + + src->curoffset += readsize; + GST_LOG_OBJECT (src, + "Returning buffer from _get of size %d, ts %" + GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT + ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT, + GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), + GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); + return GST_DATA (buf); +} + +static void +gst_httpclientsrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstHttpclientSrc *httpclientsrc; + + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_HTTPCLIENTSRC (object)); + httpclientsrc = GST_HTTPCLIENTSRC (object); + + GST_DEBUG_OBJECT (httpclientsrc, "setting property %d", prop_id); + + switch (prop_id) { + case ARG_LOCATION: { + gchar *pathstart = NULL; + gchar *location = NULL; + gchar *hostport = NULL; + gchar *portstart = NULL; + int locationlen; + g_free (httpclientsrc->location); + g_free (httpclientsrc->host); + g_free (httpclientsrc->path); + httpclientsrc->location = location = g_strdup (g_value_get_string (value)); + GST_DEBUG_OBJECT (httpclientsrc, "setting location=%s", location); + + if (strncmp(location, "http://", 7) != 0) + return; + locationlen = strlen(location); + hostport = location + 7; + GST_DEBUG_OBJECT (httpclientsrc, " hostport=%s", hostport); + + pathstart = strchr(hostport, '/'); + GST_DEBUG_OBJECT (httpclientsrc, " pathstart=%s", pathstart); + + if (pathstart) { + httpclientsrc->path = g_strdup(pathstart); + } else { + httpclientsrc->path = g_strdup("/"); + pathstart = location+locationlen; + } + hostport = g_strndup(hostport, pathstart - hostport); + portstart = strrchr(hostport, ':'); + GST_DEBUG_OBJECT (httpclientsrc, " hostport=%s portstart=%s", hostport, portstart); + if (portstart != NULL) { + httpclientsrc->host = g_strndup(hostport, portstart - hostport); + httpclientsrc->port = strtoul(portstart+1, NULL, 0); + g_free(hostport); + } else { + httpclientsrc->host = hostport; + httpclientsrc->port = 80; + } + GST_DEBUG_OBJECT (httpclientsrc, " host=%s port=%d path=%s", httpclientsrc->host, httpclientsrc->port, httpclientsrc->path); + } break; + case ARG_METHOD: + g_free (httpclientsrc->method); + httpclientsrc->method = g_strdup (g_value_get_string (value)); + break; + case ARG_PROTOCOL: + httpclientsrc->protocol = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_httpclientsrc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstHttpclientSrc *httpclientsrc; + + g_return_if_fail (GST_IS_HTTPCLIENTSRC (object)); + httpclientsrc = GST_HTTPCLIENTSRC (object); + + switch (prop_id) { + case ARG_LOCATION: + g_value_set_string (value, httpclientsrc->location); + break; + case ARG_METHOD: + g_value_set_string (value, httpclientsrc->method); + break; + case ARG_PROTOCOL: + g_value_set_enum (value, httpclientsrc->protocol); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* create a socket for connecting to remote server */ +static gboolean +gst_httpclientsrc_init_receive (GstHttpclientSrc * this) +{ + int ret; + gchar ip[256]; + struct addrinfo *addrinfo, *top_addrinfo; + int addr_family; + gchar *request = NULL; + + GST_DEBUG_OBJECT (this, "getaddrinfo %s", this->host); + ret = getaddrinfo(this->host, "http", NULL, &addrinfo); + top_addrinfo = addrinfo; + + retry: + this->addr_family = addr_family = addrinfo->ai_family; + this->server_addrlen = addrinfo->ai_addrlen; + memset(&this->server_sockaddr, 0, sizeof(this->server_sockaddr)); + memcpy(&this->server_sockaddr, addrinfo->ai_addr, addrinfo->ai_addrlen); + + /* create receiving client socket */ + GST_DEBUG_OBJECT (this, "opening receiving client socket to %s:%d\n", + this->host, this->port); + if ((this->sock_fd = socket (this->addr_family, SOCK_STREAM, 0)) == -1) { + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM); + return FALSE; + } + GST_DEBUG_OBJECT (this, "opened receiving client socket with fd %d", + this->sock_fd); + + /* look up name if we need to */ + GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip); + + /* fill in port */ + switch (this->addr_family) { + case AF_INET: + ((struct sockaddr_in *)&this->server_sockaddr)->sin_port = htons(this->port); + inet_ntop(this->addr_family, &(((struct sockaddr_in *)&this->server_sockaddr)->sin_addr), ip, sizeof(ip)); + break; + case AF_INET6: + ((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_port = htons(this->port); + inet_ntop(this->addr_family, &(((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_addr), ip, sizeof(ip)); + break; + } + if (this->addr_family == AF_INET6) { + int offset = 0; + int i; + struct in6_addr *in6_addr = &(((struct sockaddr_in6 *)&this->server_sockaddr)->sin6_addr); + for (i = 0; i < sizeof(struct in6_addr); i++) { + int b = in6_addr->s6_addr[i]; + offset += sprintf(ip+offset, ":%02x", b); + } + } + + /* connect to server */ + GST_DEBUG_OBJECT (this, "connecting to server family=%d ip=%s port=%d sockaddrlen=%d", + this->addr_family, ip, this->port, this->server_addrlen); + ret = connect (this->sock_fd, (struct sockaddr *) &this->server_sockaddr, this->server_addrlen); + + if (ret) { + switch (errno) { + case ECONNREFUSED: + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, + (_("Connection to %s:%d refused."), this->host, this->port), + (NULL)); + if (addrinfo->ai_next == NULL) + return FALSE; + break; + default: + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), + ("connect to %s:%d failed: %s", this->host, this->port, + g_strerror (errno))); + if (addrinfo->ai_next == NULL) + return FALSE; + break; + } + addrinfo = addrinfo->ai_next; + if (addrinfo) { + GST_DEBUG_OBJECT(this, "retrying with addrinfo %p", addrinfo); + goto retry; + } + } + + /* send request and headers */ + request = g_strdup_printf("%s %s HTTP/1.0\r\nHost: %s\r\n\r\n", + this->method, this->path, this->host); + GST_DEBUG_OBJECT(this, "sending request %s", request); + if (gst_tcp_socket_write(this->sock_fd, request, strlen(request)) < 0) { + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), + ("sending HTTP request to %s failed: %s", this->location, + g_strerror (errno))); + return FALSE; + } + g_free(request); + + + /* receive and discard headers */ + { + char responseline[12]; + int rc; + /* receive response line (HTTP/1.x NNN) */ + if ((rc = gst_tcp_socket_read(this->sock_fd, responseline, sizeof(responseline))) < 0) { + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), + ("reading HTTP response from %s failed: %s", this->location, + g_strerror (errno))); + return FALSE; + } + GST_DEBUG_OBJECT(this, "got %d byte response %s", rc, responseline); + + enum response_state { + RESPONSE_CHAR, + RESPONSE_CR, + RESPONSE_CRLF, + RESPONSE_CRLFCR, + RESPONSE_END_OF_HEADERS /* saw crlfcrlf */ + } response_state = RESPONSE_CHAR; + while (response_state != RESPONSE_END_OF_HEADERS) { + gchar ch; + if (gst_tcp_socket_read(this->sock_fd, &ch, sizeof(ch)) < 0) { + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL), + ("reading HTTP response from %s failed: %s", this->location, + g_strerror (errno))); + return FALSE; + } + switch (ch) { + case '\n': + switch (response_state) { + case RESPONSE_CR: response_state = RESPONSE_CRLF; break; + case RESPONSE_CRLFCR: response_state = RESPONSE_END_OF_HEADERS; break; + default: response_state = RESPONSE_CHAR; + } break; + case '\r': + switch (response_state) { + case RESPONSE_CRLF: response_state = RESPONSE_CRLFCR; break; + default: response_state = RESPONSE_CR; + } break; + default: + response_state = RESPONSE_CHAR; + } + } + } + + this->send_discont = TRUE; + this->buffer_after_discont = NULL; + GST_FLAG_SET (this, GST_HTTPCLIENTSRC_OPEN); + + /* get the caps if we're using GDP */ + if (this->protocol == GST_TCP_PROTOCOL_TYPE_GDP) { + /* if we haven't received caps yet, we should get them first */ + if (!this->caps_received) { + GstCaps *caps; + + GST_DEBUG_OBJECT (this, "getting caps through GDP"); + if (!(caps = gst_tcp_gdp_read_caps (GST_ELEMENT (this), this->sock_fd))) { + GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL), + ("Could not read caps through GDP")); + return FALSE; + } + if (!GST_IS_CAPS (caps)) { + GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL), + ("Could not read caps through GDP")); + return FALSE; + } + GST_DEBUG_OBJECT (this, "Received caps through GDP: %" GST_PTR_FORMAT, + caps); + this->caps_received = TRUE; + this->caps = caps; + } + } + return TRUE; +} + +static void +gst_httpclientsrc_close (GstHttpclientSrc * this) +{ + if (this->sock_fd != -1) { + close (this->sock_fd); + this->sock_fd = -1; + } + this->caps_received = FALSE; + if (this->caps) { + gst_caps_free (this->caps); + this->caps = NULL; + } + GST_FLAG_UNSET (this, GST_HTTPCLIENTSRC_OPEN); +} + +static GstElementStateReturn +gst_httpclientsrc_change_state (GstElement * element) +{ + g_return_val_if_fail (GST_IS_HTTPCLIENTSRC (element), GST_STATE_FAILURE); + + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (GST_FLAG_IS_SET (element, GST_HTTPCLIENTSRC_OPEN)) + gst_httpclientsrc_close (GST_HTTPCLIENTSRC (element)); + } else { + if (!GST_FLAG_IS_SET (element, GST_HTTPCLIENTSRC_OPEN)) { + if (!gst_httpclientsrc_init_receive (GST_HTTPCLIENTSRC (element))) + return GST_STATE_FAILURE; + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff -urN gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.h gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.h --- gst-plugins-0.8.7/gst/tcp/gsthttpclientsrc.h 1969-12-31 19:00:00.000000000 -0500 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsthttpclientsrc.h 2005-03-02 09:47:01.640623151 -0500 @@ -0,0 +1,98 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2004> Thomas Vander Stichele + * + * 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_HTTPCLIENTSRC_H__ +#define __GST_HTTPCLIENTSRC_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include /* sockaddr_in */ +#include /* sockaddr_in */ +#include +#include "gsttcp.h" + +#define GST_TYPE_HTTPCLIENTSRC \ + (gst_httpclientsrc_get_type()) +#define GST_HTTPCLIENTSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HTTPCLIENTSRC,GstHttpclientSrc)) +#define GST_HTTPCLIENTSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HTTPCLIENTSRC,GstHttpclientSrc)) +#define GST_IS_HTTPCLIENTSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HTTPCLIENTSRC)) +#define GST_IS_HTTPCLIENTSRC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HTTPCLIENTSRC)) + +typedef struct _GstHttpclientSrc GstHttpclientSrc; +typedef struct _GstHttpclientSrcClass GstHttpclientSrcClass; + +typedef enum GstHttpclientSrcFlags { + GST_HTTPCLIENTSRC_OPEN = GST_ELEMENT_FLAG_LAST, + + GST_HTTPCLIENTSRC_FLAG_LAST, +} GstHttpclientSrcFlags; + +struct _GstHttpclientSrc { + GstElement element; + + /* pad */ + GstPad *srcpad; + + /* server information */ + int port; + int addr_family; + gchar *method; + gchar *host; + gchar *path; + gchar *location; /* url */ + struct sockaddr_storage server_sockaddr; + int server_addrlen; + + /* socket */ + int sock_fd; + + /* number of bytes we've gotten */ + off_t curoffset; + + GstTCPProtocolType protocol; /* protocol used for reading data */ + gboolean caps_received; /* if we have received caps yet */ + GstCaps *caps; + GstClock *clock; + + gboolean send_discont; /* TRUE when we need to send a discont */ + GstBuffer *buffer_after_discont; /* temporary storage for buffer */ +}; + +struct _GstHttpclientSrcClass { + GstElementClass parent_class; +}; + +GType gst_httpclientsrc_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_HTTPCLIENTSRC_H__ */ diff -urN gst-plugins-0.8.7/gst/tcp/gsttcpplugin.c gst-plugins-0.8.7-httpsrc1/gst/tcp/gsttcpplugin.c --- gst-plugins-0.8.7/gst/tcp/gsttcpplugin.c 2004-11-05 12:15:10.000000000 -0500 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/gsttcpplugin.c 2005-03-02 09:59:33.003801791 -0500 @@ -23,6 +23,7 @@ #include "gsttcpsrc.h" #include "gsttcpsink.h" +#include "gsthttpclientsrc.h" #include "gsttcpclientsrc.h" #include "gsttcpclientsink.h" #include "gsttcpserversrc.h" @@ -59,6 +60,9 @@ if (!gst_element_register (plugin, "multifdsink", GST_RANK_NONE, GST_TYPE_MULTIFDSINK)) return FALSE; + if (!gst_element_register (plugin, "httpclientsrc", GST_RANK_NONE, + GST_TYPE_HTTPCLIENTSRC)) + return FALSE; GST_DEBUG_CATEGORY_INIT (tcp_debug, "tcp", 0, "TCP calls"); diff -urN gst-plugins-0.8.7/gst/tcp/Makefile.am gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.am --- gst-plugins-0.8.7/gst/tcp/Makefile.am 2004-11-02 02:41:44.000000000 -0500 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.am 2005-03-02 09:29:30.125528594 -0500 @@ -18,6 +18,7 @@ gsttcp.c \ gstfdset.c \ gstmultifdsink.c \ + gsthttpclientsrc.c \ gsttcpclientsrc.c gsttcpclientsink.c \ gsttcpserversrc.c gsttcpserversink.c @@ -35,6 +36,7 @@ gsttcp.h \ gstfdset.h \ gstmultifdsink.h \ + gsthttpclientsrc.h \ gsttcpclientsrc.h gsttcpclientsink.h \ gsttcpserversrc.h gsttcpserversink.h diff -urN gst-plugins-0.8.7/gst/tcp/Makefile.in gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.in --- gst-plugins-0.8.7/gst/tcp/Makefile.in 2005-01-05 05:47:55.000000000 -0500 +++ gst-plugins-0.8.7-httpsrc1/gst/tcp/Makefile.in 2005-03-02 09:33:30.515512648 -0500 @@ -99,7 +99,8 @@ am_libgsttcp_la_OBJECTS = libgsttcp_la-gsttcpplugin.lo \ libgsttcp_la-gsttcpsrc.lo libgsttcp_la-gsttcpsink.lo \ libgsttcp_la-gsttcp.lo libgsttcp_la-gstfdset.lo \ - libgsttcp_la-gstmultifdsink.lo libgsttcp_la-gsttcpclientsrc.lo \ + libgsttcp_la-gstmultifdsink.lo libgsttcp_la-gsthttpclientsrc.lo \ + libgsttcp_la-gsttcpclientsrc.lo \ libgsttcp_la-gsttcpclientsink.lo \ libgsttcp_la-gsttcpserversrc.lo \ libgsttcp_la-gsttcpserversink.lo @@ -730,6 +731,7 @@ gsttcp.c \ gstfdset.c \ gstmultifdsink.c \ + gsthttpclientsrc.c \ gsttcpclientsrc.c gsttcpclientsink.c \ gsttcpserversrc.c gsttcpserversink.c @@ -747,7 +749,7 @@ gsttcp.h \ gstfdset.h \ gstmultifdsink.h \ - gsttcpclientsrc.h gsttcpclientsink.h \ + gsthttpclientsrc.h gsttcpclientsrc.h gsttcpclientsink.h \ gsttcpserversrc.h gsttcpserversink.h CLEANFILES = $(BUILT_SOURCES) @@ -844,6 +846,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpclientsink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpplugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpserversink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttcp_la-gsttcpserversrc.Plo@am__quote@ @@ -913,6 +916,13 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -c -o libgsttcp_la-gstmultifdsink.lo `test -f 'gstmultifdsink.c' || echo '$(srcdir)/'`gstmultifdsink.c +libgsttcp_la-gsthttpclientsrc.lo: gsthttpclientsrc.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -MT libgsttcp_la-gsthttpclientsrc.lo -MD -MP -MF "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo" -c -o libgsttcp_la-gsthttpclientsrc.lo `test -f 'gsthttpclientsrc.c' || echo '$(srcdir)/'`gsthttpclientsrc.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo" "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Plo"; else rm -f "$(DEPDIR)/libgsttcp_la-gsthttpclientsrc.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsthttpclientsrc.c' object='libgsttcp_la-gsthttpclientsrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -c -o libgsttcp_la-gsthttpclientsrc.lo `test -f 'gsthttpclientsrc.c' || echo '$(srcdir)/'`gsthttpclientsrc.c + libgsttcp_la-gsttcpclientsrc.lo: gsttcpclientsrc.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttcp_la_CFLAGS) $(CFLAGS) -MT libgsttcp_la-gsttcpclientsrc.lo -MD -MP -MF "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo" -c -o libgsttcp_la-gsttcpclientsrc.lo `test -f 'gsttcpclientsrc.c' || echo '$(srcdir)/'`gsttcpclientsrc.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo" "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Plo"; else rm -f "$(DEPDIR)/libgsttcp_la-gsttcpclientsrc.Tpo"; exit 1; fi