Commit 710fa239 authored by Wim Taymans's avatar Wim Taymans

Merge branch 'master' into 0.11

parents 0af32751 9175a903
......@@ -74,6 +74,9 @@ static void authenticate (SoupSession * session, SoupMessage * msg,
SoupAuth * auth, gboolean retrying, gpointer user_data);
static void
callback (SoupSession * session, SoupMessage * msg, gpointer user_data);
static gboolean
gst_soup_http_sink_set_proxy (GstSoupHttpSink * souphttpsink,
const gchar * uri);
enum
{
......@@ -87,7 +90,7 @@ enum
PROP_PROXY_ID,
PROP_PROXY_PW,
PROP_COOKIES,
PROP_SESSION,
PROP_SESSION
};
#define DEFAULT_USER_AGENT "GStreamer souphttpsink "
......@@ -159,13 +162,11 @@ gst_soup_http_sink_class_init (GstSoupHttpSinkClass * klass)
g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
"Automatically follow HTTP redirects (HTTP Status Code 3xx)",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#if 0
g_object_class_install_property (gobject_class,
PROP_PROXY,
g_param_spec_string ("proxy", "Proxy",
"HTTP proxy server URI", "",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif
g_object_class_install_property (gobject_class,
PROP_USER_ID,
g_param_spec_string ("user-id", "user-id",
......@@ -187,7 +188,9 @@ gst_soup_http_sink_class_init (GstSoupHttpSinkClass * klass)
g_param_spec_object ("session", "session",
"SoupSession object to use for communication",
SOUP_TYPE_SESSION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_COOKIES,
g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
......@@ -195,9 +198,7 @@ static void
gst_soup_http_sink_init (GstSoupHttpSink * souphttpsink,
GstSoupHttpSinkClass * souphttpsink_class)
{
#if 0
const char *proxy;
#endif
souphttpsink->sinkpad =
gst_pad_new_from_static_template (&gst_soup_http_sink_sink_template,
......@@ -215,14 +216,12 @@ gst_soup_http_sink_init (GstSoupHttpSink * souphttpsink,
souphttpsink->proxy_pw = NULL;
souphttpsink->prop_session = NULL;
souphttpsink->timeout = 1;
#if 0
proxy = g_getenv ("http_proxy");
if (proxy && !gst_soup_http_sink_set_proxy (souphttpsink, proxy)) {
GST_WARNING_OBJECT (souphttpsink,
"The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
proxy);
}
#endif
gst_soup_http_sink_reset (souphttpsink);
}
......@@ -237,6 +236,25 @@ gst_soup_http_sink_reset (GstSoupHttpSink * souphttpsink)
}
static gboolean
gst_soup_http_sink_set_proxy (GstSoupHttpSink * souphttpsink, const gchar * uri)
{
if (souphttpsink->proxy) {
soup_uri_free (souphttpsink->proxy);
souphttpsink->proxy = NULL;
}
if (g_str_has_prefix (uri, "http://")) {
souphttpsink->proxy = soup_uri_new (uri);
} else {
gchar *new_uri = g_strconcat ("http://", uri, NULL);
souphttpsink->proxy = soup_uri_new (new_uri);
g_free (new_uri);
}
return TRUE;
}
void
gst_soup_http_sink_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
......@@ -279,10 +297,31 @@ gst_soup_http_sink_set_property (GObject * object, guint property_id,
g_free (souphttpsink->proxy_pw);
souphttpsink->proxy_pw = g_value_dup_string (value);
break;
case PROP_PROXY:
{
const gchar *proxy;
proxy = g_value_get_string (value);
if (proxy == NULL) {
GST_WARNING ("proxy property cannot be NULL");
goto done;
}
if (!gst_soup_http_sink_set_proxy (souphttpsink, proxy)) {
GST_WARNING ("badly formatted proxy URI");
goto done;
}
break;
}
case PROP_COOKIES:
g_strfreev (souphttpsink->cookies);
souphttpsink->cookies = g_strdupv (g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
done:
g_mutex_unlock (souphttpsink->mutex);
}
......@@ -317,7 +356,19 @@ gst_soup_http_sink_get_property (GObject * object, guint property_id,
case PROP_PROXY_PW:
g_value_set_string (value, souphttpsink->proxy_pw);
break;
case PROP_PROXY:
if (souphttpsink->proxy == NULL)
g_value_set_static_string (value, "");
else {
char *proxy = soup_uri_to_string (souphttpsink->proxy, FALSE);
g_value_set_string (value, proxy);
g_free (proxy);
}
break;
case PROP_COOKIES:
g_value_set_boxed (value, g_strdupv (souphttpsink->cookies));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
......@@ -349,6 +400,8 @@ gst_soup_http_sink_finalize (GObject * object)
g_free (souphttpsink->user_pw);
g_free (souphttpsink->proxy_id);
g_free (souphttpsink->proxy_pw);
if (souphttpsink->proxy)
soup_uri_free (souphttpsink->proxy);
g_free (souphttpsink->location);
g_cond_free (souphttpsink->cond);
......@@ -482,17 +535,17 @@ gst_soup_http_sink_event (GstBaseSink * sink, GstEvent * event)
{
GstSoupHttpSink *souphttpsink = GST_SOUP_HTTP_SINK (sink);
GST_DEBUG ("event");
GST_DEBUG_OBJECT (souphttpsink, "event");
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
GST_DEBUG ("got eos");
GST_DEBUG_OBJECT (souphttpsink, "got eos");
g_mutex_lock (souphttpsink->mutex);
while (souphttpsink->message) {
GST_DEBUG ("waiting");
GST_DEBUG_OBJECT (souphttpsink, "waiting");
g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
}
g_mutex_unlock (souphttpsink->mutex);
GST_DEBUG ("finished eos");
GST_DEBUG_OBJECT (souphttpsink, "finished eos");
}
return TRUE;
......@@ -536,8 +589,6 @@ send_message_locked (GstSoupHttpSink * souphttpsink)
souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
//soup_message_body_set_accumulate (souphttpsink->message->request_body, TRUE);
n = 0;
if (souphttpsink->offset == 0) {
for (g = souphttpsink->streamheader_buffers; g; g = g_list_next (g)) {
......@@ -579,10 +630,11 @@ send_message_locked (GstSoupHttpSink * souphttpsink)
souphttpsink->sent_buffers = souphttpsink->queued_buffers;
souphttpsink->queued_buffers = NULL;
GST_DEBUG ("queue message %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
GST_DEBUG_OBJECT (souphttpsink,
"queue message %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
souphttpsink->offset, n);
soup_session_queue_message (souphttpsink->session,
souphttpsink->message, callback, souphttpsink);
soup_session_queue_message (souphttpsink->session, souphttpsink->message,
callback, souphttpsink);
souphttpsink->offset += n;
}
......@@ -631,6 +683,7 @@ gst_soup_http_sink_render (GstBaseSink * sink, GstBuffer * buffer)
gboolean wake;
if (souphttpsink->status_code != 0) {
/* FIXME we should allow a moderate amount of retries. */
GST_ELEMENT_ERROR (souphttpsink, RESOURCE, WRITE,
("Could not write to HTTP URI"),
("error: %d %s", souphttpsink->status_code,
......@@ -646,7 +699,6 @@ gst_soup_http_sink_render (GstBaseSink * sink, GstBuffer * buffer)
if (wake) {
source = g_idle_source_new ();
//g_source_set_priority (source, G_PRIORITY_DEFAULT);
g_source_set_callback (source, (GSourceFunc) (send_message),
souphttpsink, NULL);
g_source_attach (source, souphttpsink->context);
......
......@@ -62,10 +62,12 @@ struct _GstSoupHttpSink
char *location;
char *user_id;
char *user_pw;
SoupURI *proxy;
char *proxy_id;
char *proxy_pw;
char *user_agent;
gboolean automatic_redirect;
gchar **cookies;
};
......
......@@ -479,8 +479,13 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
if (templ->direction != GST_PAD_SINK)
goto not_sink_pad;
#if GLIB_CHECK_VERSION(2,29,5)
channels = g_atomic_int_add (&self->channels, 1);
padnumber = g_atomic_int_add (&self->padcounter, 1);
#else
channels = g_atomic_int_exchange_and_add (&self->channels, 1);
padnumber = g_atomic_int_exchange_and_add (&self->padcounter, 1);
#endif
pad_name = g_strdup_printf ("sink%d", padnumber);
new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
......
This diff is collapsed.
......@@ -55,11 +55,6 @@ typedef struct _GstMatroskaDemux {
guint num_a_streams;
guint num_t_streams;
/* metadata */
gchar *muxing_app;
gchar *writing_app;
gint64 created;
/* state */
gboolean streaming;
guint level_up;
......@@ -68,16 +63,12 @@ typedef struct _GstMatroskaDemux {
/* did we parse cues/tracks/segmentinfo already? */
gboolean tracks_parsed;
gboolean segmentinfo_parsed;
gboolean attachments_parsed;
GList *tags_parsed;
GList *seek_parsed;
/* cluster positions (optional) */
GArray *clusters;
/* keeping track of playback position */
GstSegment segment;
gboolean segment_running;
GstClockTime last_stop_end;
......
This diff is collapsed.
......@@ -60,11 +60,6 @@ typedef struct _GstMatroskaParse {
gboolean pushed_headers;
GstClockTime last_timestamp;
/* metadata */
gchar *muxing_app;
gchar *writing_app;
gint64 created;
/* state */
//gboolean streaming;
guint level_up;
......@@ -73,13 +68,9 @@ typedef struct _GstMatroskaParse {
/* did we parse cues/tracks/segmentinfo already? */
gboolean tracks_parsed;
gboolean segmentinfo_parsed;
gboolean attachments_parsed;
GList *tags_parsed;
GList *seek_parsed;
/* keeping track of playback position */
GstSegment segment;
gboolean segment_running;
GstClockTime last_stop_end;
......
......@@ -36,6 +36,9 @@
#include <bzlib.h>
#endif
#include <gst/tag/tag.h>
#include <gst/base/gsttypefindhelper.h>
#include "lzo.h"
#include "ebml-read.h"
......@@ -484,6 +487,242 @@ gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
return gst_ebml_read_skip (ebml);
}
static GstFlowReturn
gst_matroska_read_common_parse_attached_file (GstMatroskaReadCommon * common,
GstEbmlRead * ebml, GstTagList * taglist)
{
guint32 id;
GstFlowReturn ret;
gchar *description = NULL;
gchar *filename = NULL;
gchar *mimetype = NULL;
guint8 *data = NULL;
guint64 datalen = 0;
DEBUG_ELEMENT_START (common, ebml, "AttachedFile");
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
return ret;
}
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
/* read all sub-entries */
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
break;
switch (id) {
case GST_MATROSKA_ID_FILEDESCRIPTION:
if (description) {
GST_WARNING_OBJECT (common, "FileDescription can only appear once");
break;
}
ret = gst_ebml_read_utf8 (ebml, &id, &description);
GST_DEBUG_OBJECT (common, "FileDescription: %s",
GST_STR_NULL (description));
break;
case GST_MATROSKA_ID_FILENAME:
if (filename) {
GST_WARNING_OBJECT (common, "FileName can only appear once");
break;
}
ret = gst_ebml_read_utf8 (ebml, &id, &filename);
GST_DEBUG_OBJECT (common, "FileName: %s", GST_STR_NULL (filename));
break;
case GST_MATROSKA_ID_FILEMIMETYPE:
if (mimetype) {
GST_WARNING_OBJECT (common, "FileMimeType can only appear once");
break;
}
ret = gst_ebml_read_ascii (ebml, &id, &mimetype);
GST_DEBUG_OBJECT (common, "FileMimeType: %s", GST_STR_NULL (mimetype));
break;
case GST_MATROSKA_ID_FILEDATA:
if (data) {
GST_WARNING_OBJECT (common, "FileData can only appear once");
break;
}
ret = gst_ebml_read_binary (ebml, &id, &data, &datalen);
GST_DEBUG_OBJECT (common, "FileData of size %" G_GUINT64_FORMAT,
datalen);
break;
default:
ret = gst_matroska_read_common_parse_skip (common, ebml,
"AttachedFile", id);
break;
case GST_MATROSKA_ID_FILEUID:
ret = gst_ebml_read_skip (ebml);
break;
}
}
DEBUG_ELEMENT_STOP (common, ebml, "AttachedFile", ret);
if (filename && mimetype && data && datalen > 0) {
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
GstBuffer *tagbuffer = NULL;
GstCaps *caps;
gchar *filename_lc = g_utf8_strdown (filename, -1);
GST_DEBUG_OBJECT (common, "Creating tag for attachment with "
"filename '%s', mimetype '%s', description '%s', "
"size %" G_GUINT64_FORMAT, filename, mimetype,
GST_STR_NULL (description), datalen);
/* TODO: better heuristics for different image types */
if (strstr (filename_lc, "cover")) {
if (strstr (filename_lc, "back"))
image_type = GST_TAG_IMAGE_TYPE_BACK_COVER;
else
image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
} else if (g_str_has_prefix (mimetype, "image/") ||
g_str_has_suffix (filename_lc, "png") ||
g_str_has_suffix (filename_lc, "jpg") ||
g_str_has_suffix (filename_lc, "jpeg") ||
g_str_has_suffix (filename_lc, "gif") ||
g_str_has_suffix (filename_lc, "bmp")) {
image_type = GST_TAG_IMAGE_TYPE_UNDEFINED;
}
g_free (filename_lc);
/* First try to create an image tag buffer from this */
if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
tagbuffer =
gst_tag_image_data_to_image_buffer (data, datalen, image_type);
if (!tagbuffer)
image_type = GST_TAG_IMAGE_TYPE_NONE;
}
/* if this failed create an attachment buffer */
if (!tagbuffer) {
tagbuffer = gst_buffer_new_and_alloc (datalen);
memcpy (GST_BUFFER_DATA (tagbuffer), data, datalen);
GST_BUFFER_SIZE (tagbuffer) = datalen;
caps = gst_type_find_helper_for_buffer (NULL, tagbuffer, NULL);
if (caps == NULL)
caps = gst_caps_new_simple (mimetype, NULL);
gst_buffer_set_caps (tagbuffer, caps);
gst_caps_unref (caps);
}
/* Set filename and description on the caps */
caps = GST_BUFFER_CAPS (tagbuffer);
gst_caps_set_simple (caps, "filename", G_TYPE_STRING, filename, NULL);
if (description)
gst_caps_set_simple (caps, "description", G_TYPE_STRING, description,
NULL);
GST_DEBUG_OBJECT (common,
"Created attachment buffer with caps: %" GST_PTR_FORMAT, caps);
/* and append to the tag list */
if (image_type != GST_TAG_IMAGE_TYPE_NONE)
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, tagbuffer,
NULL);
else
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_ATTACHMENT,
tagbuffer, NULL);
}
g_free (filename);
g_free (mimetype);
g_free (data);
g_free (description);
return ret;
}
GstFlowReturn
gst_matroska_read_common_parse_attachments (GstMatroskaReadCommon * common,
GstElement * el, GstEbmlRead * ebml)
{
guint32 id;
GstFlowReturn ret = GST_FLOW_OK;
GstTagList *taglist;
DEBUG_ELEMENT_START (common, ebml, "Attachments");
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
return ret;
}
taglist = gst_tag_list_new ();
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
break;
switch (id) {
case GST_MATROSKA_ID_ATTACHEDFILE:
ret = gst_matroska_read_common_parse_attached_file (common, ebml,
taglist);
break;
default:
ret = gst_matroska_read_common_parse_skip (common, ebml,
"Attachments", id);
break;
}
}
DEBUG_ELEMENT_STOP (common, ebml, "Attachments", ret);
if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
GST_DEBUG_OBJECT (common, "Storing attachment tags");
gst_matroska_read_common_found_global_tag (common, el, taglist);
} else {
GST_DEBUG_OBJECT (common, "No valid attachments found");
gst_tag_list_free (taglist);
}
common->attachments_parsed = TRUE;
return ret;
}
GstFlowReturn
gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
GstEbmlRead * ebml)
{
guint32 id;
GstFlowReturn ret = GST_FLOW_OK;
GST_WARNING_OBJECT (common, "Parsing of chapters not implemented yet");
/* TODO: implement parsing of chapters */
DEBUG_ELEMENT_START (common, ebml, "Chapters");
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
return ret;
}
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
break;
switch (id) {
default:
ret = gst_ebml_read_skip (ebml);
break;
}
}
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
return ret;
}
GstFlowReturn
gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
GstEbmlRead * ebml)
......@@ -953,6 +1192,360 @@ gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
return ret;
}
GstFlowReturn
gst_matroska_read_common_parse_info (GstMatroskaReadCommon * common,
GstElement * el, GstEbmlRead * ebml)
{
GstFlowReturn ret = GST_FLOW_OK;
gdouble dur_f = -1.0;
guint32 id;
DEBUG_ELEMENT_START (common, ebml, "SegmentInfo");
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
return ret;
}
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
break;
switch (id) {
/* cluster timecode */
case GST_MATROSKA_ID_TIMECODESCALE:{
guint64 num;
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
break;
GST_DEBUG_OBJECT (common, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
common->time_scale = num;
break;
}
case GST_MATROSKA_ID_DURATION:{
if ((ret = gst_ebml_read_float (ebml, &id, &dur_f)) != GST_FLOW_OK)
break;
if (dur_f <= 0.0) {
GST_WARNING_OBJECT (common, "Invalid duration %lf", dur_f);
break;
}
GST_DEBUG_OBJECT (common, "Duration: %lf", dur_f);
break;
}
case GST_MATROSKA_ID_WRITINGAPP:{
gchar *text;
if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
break;
GST_DEBUG_OBJECT (common, "WritingApp: %s", GST_STR_NULL (text));
common->writing_app = text;
break;
}
case GST_MATROSKA_ID_MUXINGAPP:{
gchar *text;
if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
break;
GST_DEBUG_OBJECT (common, "MuxingApp: %s", GST_STR_NULL (text));
common->muxing_app = text;
break;
}