mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
Merge branch 'master' into 0.11
This commit is contained in:
commit
710fa239d5
10 changed files with 832 additions and 1342 deletions
|
@ -74,6 +74,9 @@ static void authenticate (SoupSession * session, SoupMessage * msg,
|
||||||
SoupAuth * auth, gboolean retrying, gpointer user_data);
|
SoupAuth * auth, gboolean retrying, gpointer user_data);
|
||||||
static void
|
static void
|
||||||
callback (SoupSession * session, SoupMessage * msg, gpointer user_data);
|
callback (SoupSession * session, SoupMessage * msg, gpointer user_data);
|
||||||
|
static gboolean
|
||||||
|
gst_soup_http_sink_set_proxy (GstSoupHttpSink * souphttpsink,
|
||||||
|
const gchar * uri);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -87,7 +90,7 @@ enum
|
||||||
PROP_PROXY_ID,
|
PROP_PROXY_ID,
|
||||||
PROP_PROXY_PW,
|
PROP_PROXY_PW,
|
||||||
PROP_COOKIES,
|
PROP_COOKIES,
|
||||||
PROP_SESSION,
|
PROP_SESSION
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_USER_AGENT "GStreamer souphttpsink "
|
#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",
|
g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
|
||||||
"Automatically follow HTTP redirects (HTTP Status Code 3xx)",
|
"Automatically follow HTTP redirects (HTTP Status Code 3xx)",
|
||||||
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
#if 0
|
|
||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class,
|
||||||
PROP_PROXY,
|
PROP_PROXY,
|
||||||
g_param_spec_string ("proxy", "Proxy",
|
g_param_spec_string ("proxy", "Proxy",
|
||||||
"HTTP proxy server URI", "",
|
"HTTP proxy server URI", "",
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
#endif
|
|
||||||
g_object_class_install_property (gobject_class,
|
g_object_class_install_property (gobject_class,
|
||||||
PROP_USER_ID,
|
PROP_USER_ID,
|
||||||
g_param_spec_string ("user-id", "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",
|
g_param_spec_object ("session", "session",
|
||||||
"SoupSession object to use for communication",
|
"SoupSession object to use for communication",
|
||||||
SOUP_TYPE_SESSION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
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,
|
gst_soup_http_sink_init (GstSoupHttpSink * souphttpsink,
|
||||||
GstSoupHttpSinkClass * souphttpsink_class)
|
GstSoupHttpSinkClass * souphttpsink_class)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
const char *proxy;
|
const char *proxy;
|
||||||
#endif
|
|
||||||
|
|
||||||
souphttpsink->sinkpad =
|
souphttpsink->sinkpad =
|
||||||
gst_pad_new_from_static_template (&gst_soup_http_sink_sink_template,
|
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->proxy_pw = NULL;
|
||||||
souphttpsink->prop_session = NULL;
|
souphttpsink->prop_session = NULL;
|
||||||
souphttpsink->timeout = 1;
|
souphttpsink->timeout = 1;
|
||||||
#if 0
|
|
||||||
proxy = g_getenv ("http_proxy");
|
proxy = g_getenv ("http_proxy");
|
||||||
if (proxy && !gst_soup_http_sink_set_proxy (souphttpsink, proxy)) {
|
if (proxy && !gst_soup_http_sink_set_proxy (souphttpsink, proxy)) {
|
||||||
GST_WARNING_OBJECT (souphttpsink,
|
GST_WARNING_OBJECT (souphttpsink,
|
||||||
"The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
|
"The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
|
||||||
proxy);
|
proxy);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
gst_soup_http_sink_reset (souphttpsink);
|
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
|
void
|
||||||
gst_soup_http_sink_set_property (GObject * object, guint property_id,
|
gst_soup_http_sink_set_property (GObject * object, guint property_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
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);
|
g_free (souphttpsink->proxy_pw);
|
||||||
souphttpsink->proxy_pw = g_value_dup_string (value);
|
souphttpsink->proxy_pw = g_value_dup_string (value);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
g_mutex_unlock (souphttpsink->mutex);
|
g_mutex_unlock (souphttpsink->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +356,19 @@ gst_soup_http_sink_get_property (GObject * object, guint property_id,
|
||||||
case PROP_PROXY_PW:
|
case PROP_PROXY_PW:
|
||||||
g_value_set_string (value, souphttpsink->proxy_pw);
|
g_value_set_string (value, souphttpsink->proxy_pw);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -349,6 +400,8 @@ gst_soup_http_sink_finalize (GObject * object)
|
||||||
g_free (souphttpsink->user_pw);
|
g_free (souphttpsink->user_pw);
|
||||||
g_free (souphttpsink->proxy_id);
|
g_free (souphttpsink->proxy_id);
|
||||||
g_free (souphttpsink->proxy_pw);
|
g_free (souphttpsink->proxy_pw);
|
||||||
|
if (souphttpsink->proxy)
|
||||||
|
soup_uri_free (souphttpsink->proxy);
|
||||||
g_free (souphttpsink->location);
|
g_free (souphttpsink->location);
|
||||||
|
|
||||||
g_cond_free (souphttpsink->cond);
|
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);
|
GstSoupHttpSink *souphttpsink = GST_SOUP_HTTP_SINK (sink);
|
||||||
|
|
||||||
GST_DEBUG ("event");
|
GST_DEBUG_OBJECT (souphttpsink, "event");
|
||||||
|
|
||||||
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||||
GST_DEBUG ("got eos");
|
GST_DEBUG_OBJECT (souphttpsink, "got eos");
|
||||||
g_mutex_lock (souphttpsink->mutex);
|
g_mutex_lock (souphttpsink->mutex);
|
||||||
while (souphttpsink->message) {
|
while (souphttpsink->message) {
|
||||||
GST_DEBUG ("waiting");
|
GST_DEBUG_OBJECT (souphttpsink, "waiting");
|
||||||
g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
|
g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
|
||||||
}
|
}
|
||||||
g_mutex_unlock (souphttpsink->mutex);
|
g_mutex_unlock (souphttpsink->mutex);
|
||||||
GST_DEBUG ("finished eos");
|
GST_DEBUG_OBJECT (souphttpsink, "finished eos");
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -536,8 +589,6 @@ send_message_locked (GstSoupHttpSink * souphttpsink)
|
||||||
|
|
||||||
souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
|
souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
|
||||||
|
|
||||||
//soup_message_body_set_accumulate (souphttpsink->message->request_body, TRUE);
|
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
if (souphttpsink->offset == 0) {
|
if (souphttpsink->offset == 0) {
|
||||||
for (g = souphttpsink->streamheader_buffers; g; g = g_list_next (g)) {
|
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->sent_buffers = souphttpsink->queued_buffers;
|
||||||
souphttpsink->queued_buffers = NULL;
|
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);
|
souphttpsink->offset, n);
|
||||||
soup_session_queue_message (souphttpsink->session,
|
soup_session_queue_message (souphttpsink->session, souphttpsink->message,
|
||||||
souphttpsink->message, callback, souphttpsink);
|
callback, souphttpsink);
|
||||||
|
|
||||||
souphttpsink->offset += n;
|
souphttpsink->offset += n;
|
||||||
}
|
}
|
||||||
|
@ -631,6 +683,7 @@ gst_soup_http_sink_render (GstBaseSink * sink, GstBuffer * buffer)
|
||||||
gboolean wake;
|
gboolean wake;
|
||||||
|
|
||||||
if (souphttpsink->status_code != 0) {
|
if (souphttpsink->status_code != 0) {
|
||||||
|
/* FIXME we should allow a moderate amount of retries. */
|
||||||
GST_ELEMENT_ERROR (souphttpsink, RESOURCE, WRITE,
|
GST_ELEMENT_ERROR (souphttpsink, RESOURCE, WRITE,
|
||||||
("Could not write to HTTP URI"),
|
("Could not write to HTTP URI"),
|
||||||
("error: %d %s", souphttpsink->status_code,
|
("error: %d %s", souphttpsink->status_code,
|
||||||
|
@ -646,7 +699,6 @@ gst_soup_http_sink_render (GstBaseSink * sink, GstBuffer * buffer)
|
||||||
|
|
||||||
if (wake) {
|
if (wake) {
|
||||||
source = g_idle_source_new ();
|
source = g_idle_source_new ();
|
||||||
//g_source_set_priority (source, G_PRIORITY_DEFAULT);
|
|
||||||
g_source_set_callback (source, (GSourceFunc) (send_message),
|
g_source_set_callback (source, (GSourceFunc) (send_message),
|
||||||
souphttpsink, NULL);
|
souphttpsink, NULL);
|
||||||
g_source_attach (source, souphttpsink->context);
|
g_source_attach (source, souphttpsink->context);
|
||||||
|
|
|
@ -62,10 +62,12 @@ struct _GstSoupHttpSink
|
||||||
char *location;
|
char *location;
|
||||||
char *user_id;
|
char *user_id;
|
||||||
char *user_pw;
|
char *user_pw;
|
||||||
|
SoupURI *proxy;
|
||||||
char *proxy_id;
|
char *proxy_id;
|
||||||
char *proxy_pw;
|
char *proxy_pw;
|
||||||
char *user_agent;
|
char *user_agent;
|
||||||
gboolean automatic_redirect;
|
gboolean automatic_redirect;
|
||||||
|
gchar **cookies;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -479,8 +479,13 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||||
if (templ->direction != GST_PAD_SINK)
|
if (templ->direction != GST_PAD_SINK)
|
||||||
goto not_sink_pad;
|
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);
|
channels = g_atomic_int_exchange_and_add (&self->channels, 1);
|
||||||
padnumber = g_atomic_int_exchange_and_add (&self->padcounter, 1);
|
padnumber = g_atomic_int_exchange_and_add (&self->padcounter, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
pad_name = g_strdup_printf ("sink%d", padnumber);
|
pad_name = g_strdup_printf ("sink%d", padnumber);
|
||||||
new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
|
new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -55,11 +55,6 @@ typedef struct _GstMatroskaDemux {
|
||||||
guint num_a_streams;
|
guint num_a_streams;
|
||||||
guint num_t_streams;
|
guint num_t_streams;
|
||||||
|
|
||||||
/* metadata */
|
|
||||||
gchar *muxing_app;
|
|
||||||
gchar *writing_app;
|
|
||||||
gint64 created;
|
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
gboolean streaming;
|
gboolean streaming;
|
||||||
guint level_up;
|
guint level_up;
|
||||||
|
@ -68,16 +63,12 @@ typedef struct _GstMatroskaDemux {
|
||||||
|
|
||||||
/* did we parse cues/tracks/segmentinfo already? */
|
/* did we parse cues/tracks/segmentinfo already? */
|
||||||
gboolean tracks_parsed;
|
gboolean tracks_parsed;
|
||||||
gboolean segmentinfo_parsed;
|
|
||||||
gboolean attachments_parsed;
|
|
||||||
GList *tags_parsed;
|
|
||||||
GList *seek_parsed;
|
GList *seek_parsed;
|
||||||
|
|
||||||
/* cluster positions (optional) */
|
/* cluster positions (optional) */
|
||||||
GArray *clusters;
|
GArray *clusters;
|
||||||
|
|
||||||
/* keeping track of playback position */
|
/* keeping track of playback position */
|
||||||
GstSegment segment;
|
|
||||||
gboolean segment_running;
|
gboolean segment_running;
|
||||||
GstClockTime last_stop_end;
|
GstClockTime last_stop_end;
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,6 @@
|
||||||
|
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
|
|
||||||
#include <gst/base/gsttypefindhelper.h>
|
|
||||||
|
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
|
|
||||||
#include "matroska-parse.h"
|
#include "matroska-parse.h"
|
||||||
|
@ -226,8 +224,8 @@ gst_matroska_parse_init (GstMatroskaParse * parse,
|
||||||
/* initial stream no. */
|
/* initial stream no. */
|
||||||
parse->common.src = NULL;
|
parse->common.src = NULL;
|
||||||
|
|
||||||
parse->writing_app = NULL;
|
parse->common.writing_app = NULL;
|
||||||
parse->muxing_app = NULL;
|
parse->common.muxing_app = NULL;
|
||||||
parse->common.index = NULL;
|
parse->common.index = NULL;
|
||||||
parse->common.global_tags = NULL;
|
parse->common.global_tags = NULL;
|
||||||
|
|
||||||
|
@ -306,10 +304,10 @@ gst_matroska_parse_reset (GstElement * element)
|
||||||
parse->num_v_streams = 0;
|
parse->num_v_streams = 0;
|
||||||
|
|
||||||
/* reset media info */
|
/* reset media info */
|
||||||
g_free (parse->writing_app);
|
g_free (parse->common.writing_app);
|
||||||
parse->writing_app = NULL;
|
parse->common.writing_app = NULL;
|
||||||
g_free (parse->muxing_app);
|
g_free (parse->common.muxing_app);
|
||||||
parse->muxing_app = NULL;
|
parse->common.muxing_app = NULL;
|
||||||
|
|
||||||
/* reset indexes */
|
/* reset indexes */
|
||||||
if (parse->common.index) {
|
if (parse->common.index) {
|
||||||
|
@ -320,24 +318,24 @@ gst_matroska_parse_reset (GstElement * element)
|
||||||
/* reset timers */
|
/* reset timers */
|
||||||
parse->clock = NULL;
|
parse->clock = NULL;
|
||||||
parse->common.time_scale = 1000000;
|
parse->common.time_scale = 1000000;
|
||||||
parse->created = G_MININT64;
|
parse->common.created = G_MININT64;
|
||||||
|
|
||||||
parse->common.index_parsed = FALSE;
|
parse->common.index_parsed = FALSE;
|
||||||
parse->tracks_parsed = FALSE;
|
parse->tracks_parsed = FALSE;
|
||||||
parse->segmentinfo_parsed = FALSE;
|
parse->common.segmentinfo_parsed = FALSE;
|
||||||
parse->attachments_parsed = FALSE;
|
parse->common.attachments_parsed = FALSE;
|
||||||
|
|
||||||
g_list_foreach (parse->tags_parsed,
|
g_list_foreach (parse->common.tags_parsed,
|
||||||
(GFunc) gst_matroska_parse_free_parsed_el, NULL);
|
(GFunc) gst_matroska_parse_free_parsed_el, NULL);
|
||||||
g_list_free (parse->tags_parsed);
|
g_list_free (parse->common.tags_parsed);
|
||||||
parse->tags_parsed = NULL;
|
parse->common.tags_parsed = NULL;
|
||||||
|
|
||||||
g_list_foreach (parse->seek_parsed,
|
g_list_foreach (parse->seek_parsed,
|
||||||
(GFunc) gst_matroska_parse_free_parsed_el, NULL);
|
(GFunc) gst_matroska_parse_free_parsed_el, NULL);
|
||||||
g_list_free (parse->seek_parsed);
|
g_list_free (parse->seek_parsed);
|
||||||
parse->seek_parsed = NULL;
|
parse->seek_parsed = NULL;
|
||||||
|
|
||||||
gst_segment_init (&parse->segment, GST_FORMAT_TIME);
|
gst_segment_init (&parse->common.segment, GST_FORMAT_TIME);
|
||||||
parse->last_stop_end = GST_CLOCK_TIME_NONE;
|
parse->last_stop_end = GST_CLOCK_TIME_NONE;
|
||||||
parse->seek_block = 0;
|
parse->seek_block = 0;
|
||||||
|
|
||||||
|
@ -1111,7 +1109,7 @@ gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
|
||||||
gst_query_set_position (query, GST_FORMAT_TIME, context->pos);
|
gst_query_set_position (query, GST_FORMAT_TIME, context->pos);
|
||||||
else
|
else
|
||||||
gst_query_set_position (query, GST_FORMAT_TIME,
|
gst_query_set_position (query, GST_FORMAT_TIME,
|
||||||
parse->segment.last_stop);
|
parse->common.segment.last_stop);
|
||||||
GST_OBJECT_UNLOCK (parse);
|
GST_OBJECT_UNLOCK (parse);
|
||||||
} else if (format == GST_FORMAT_DEFAULT && context
|
} else if (format == GST_FORMAT_DEFAULT && context
|
||||||
&& context->default_duration) {
|
&& context->default_duration) {
|
||||||
|
@ -1136,13 +1134,13 @@ gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
|
||||||
if (format == GST_FORMAT_TIME) {
|
if (format == GST_FORMAT_TIME) {
|
||||||
GST_OBJECT_LOCK (parse);
|
GST_OBJECT_LOCK (parse);
|
||||||
gst_query_set_duration (query, GST_FORMAT_TIME,
|
gst_query_set_duration (query, GST_FORMAT_TIME,
|
||||||
parse->segment.duration);
|
parse->common.segment.duration);
|
||||||
GST_OBJECT_UNLOCK (parse);
|
GST_OBJECT_UNLOCK (parse);
|
||||||
} else if (format == GST_FORMAT_DEFAULT && context
|
} else if (format == GST_FORMAT_DEFAULT && context
|
||||||
&& context->default_duration) {
|
&& context->default_duration) {
|
||||||
GST_OBJECT_LOCK (parse);
|
GST_OBJECT_LOCK (parse);
|
||||||
gst_query_set_duration (query, GST_FORMAT_DEFAULT,
|
gst_query_set_duration (query, GST_FORMAT_DEFAULT,
|
||||||
parse->segment.duration / context->default_duration);
|
parse->common.segment.duration / context->default_duration);
|
||||||
GST_OBJECT_UNLOCK (parse);
|
GST_OBJECT_UNLOCK (parse);
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (parse,
|
GST_DEBUG_OBJECT (parse,
|
||||||
|
@ -1165,7 +1163,7 @@ gst_matroska_parse_query (GstMatroskaParse * parse, GstPad * pad,
|
||||||
seekable = parse->seekable;
|
seekable = parse->seekable;
|
||||||
|
|
||||||
gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
|
gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
|
||||||
0, parse->segment.duration);
|
0, parse->common.segment.duration);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1354,7 +1352,7 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
|
||||||
|
|
||||||
/* copy segment, we need this because we still need the old
|
/* copy segment, we need this because we still need the old
|
||||||
* segment when we close the current segment. */
|
* segment when we close the current segment. */
|
||||||
memcpy (&seeksegment, &parse->segment, sizeof (GstSegment));
|
memcpy (&seeksegment, &parse->common.segment, sizeof (GstSegment));
|
||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
GST_DEBUG_OBJECT (parse, "configuring seek");
|
GST_DEBUG_OBJECT (parse, "configuring seek");
|
||||||
|
@ -1559,594 +1557,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|
||||||
{
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
gdouble dur_f = -1.0;
|
|
||||||
guint32 id;
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (parse, ebml, "SegmentInfo");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, 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 (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
|
|
||||||
parse->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 (parse, "Invalid duration %lf", dur_f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (parse, "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 (parse, "WritingApp: %s", GST_STR_NULL (text));
|
|
||||||
parse->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 (parse, "MuxingApp: %s", GST_STR_NULL (text));
|
|
||||||
parse->muxing_app = text;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GST_MATROSKA_ID_DATEUTC:{
|
|
||||||
gint64 time;
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_date (ebml, &id, &time)) != GST_FLOW_OK)
|
|
||||||
break;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (parse, "DateUTC: %" G_GINT64_FORMAT, time);
|
|
||||||
parse->created = time;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GST_MATROSKA_ID_TITLE:{
|
|
||||||
gchar *text;
|
|
||||||
GstTagList *taglist;
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
|
|
||||||
break;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (parse, "Title: %s", GST_STR_NULL (text));
|
|
||||||
taglist = gst_tag_list_new ();
|
|
||||||
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text,
|
|
||||||
NULL);
|
|
||||||
gst_matroska_read_common_found_global_tag (&parse->common,
|
|
||||||
GST_ELEMENT_CAST (parse), taglist);
|
|
||||||
g_free (text);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"SegmentInfo", id);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* fall through */
|
|
||||||
case GST_MATROSKA_ID_SEGMENTUID:
|
|
||||||
case GST_MATROSKA_ID_SEGMENTFILENAME:
|
|
||||||
case GST_MATROSKA_ID_PREVUID:
|
|
||||||
case GST_MATROSKA_ID_PREVFILENAME:
|
|
||||||
case GST_MATROSKA_ID_NEXTUID:
|
|
||||||
case GST_MATROSKA_ID_NEXTFILENAME:
|
|
||||||
case GST_MATROSKA_ID_SEGMENTFAMILY:
|
|
||||||
case GST_MATROSKA_ID_CHAPTERTRANSLATE:
|
|
||||||
ret = gst_ebml_read_skip (ebml);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dur_f > 0.0) {
|
|
||||||
GstClockTime dur_u;
|
|
||||||
|
|
||||||
dur_u = gst_gdouble_to_guint64 (dur_f *
|
|
||||||
gst_guint64_to_gdouble (parse->common.time_scale));
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
|
|
||||||
gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "SegmentInfo", ret);
|
|
||||||
|
|
||||||
parse->segmentinfo_parsed = TRUE;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse,
|
|
||||||
GstEbmlRead * ebml, GstTagList ** p_taglist)
|
|
||||||
{
|
|
||||||
/* FIXME: check if there are more useful mappings */
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
const gchar *matroska_tagname;
|
|
||||||
const gchar *gstreamer_tagname;
|
|
||||||
}
|
|
||||||
tag_conv[] = {
|
|
||||||
{
|
|
||||||
GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, {
|
|
||||||
GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
|
|
||||||
GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
|
|
||||||
GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
|
|
||||||
GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
|
|
||||||
GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
|
|
||||||
GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
|
|
||||||
GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
|
|
||||||
GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
|
|
||||||
GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
|
|
||||||
};
|
|
||||||
GstFlowReturn ret;
|
|
||||||
guint32 id;
|
|
||||||
gchar *value = NULL;
|
|
||||||
gchar *tag = NULL;
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (parse, ebml, "SimpleTag");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "SimpleTag", 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_TAGNAME:
|
|
||||||
g_free (tag);
|
|
||||||
tag = NULL;
|
|
||||||
ret = gst_ebml_read_ascii (ebml, &id, &tag);
|
|
||||||
GST_DEBUG_OBJECT (parse, "TagName: %s", GST_STR_NULL (tag));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GST_MATROSKA_ID_TAGSTRING:
|
|
||||||
g_free (value);
|
|
||||||
value = NULL;
|
|
||||||
ret = gst_ebml_read_utf8 (ebml, &id, &value);
|
|
||||||
GST_DEBUG_OBJECT (parse, "TagString: %s", GST_STR_NULL (value));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"SimpleTag", id);
|
|
||||||
break;
|
|
||||||
/* fall-through */
|
|
||||||
|
|
||||||
case GST_MATROSKA_ID_TAGLANGUAGE:
|
|
||||||
case GST_MATROSKA_ID_TAGDEFAULT:
|
|
||||||
case GST_MATROSKA_ID_TAGBINARY:
|
|
||||||
ret = gst_ebml_read_skip (ebml);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "SimpleTag", ret);
|
|
||||||
|
|
||||||
if (tag && value) {
|
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
|
|
||||||
const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
|
|
||||||
|
|
||||||
const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
|
|
||||||
|
|
||||||
if (strcmp (tagname_mkv, tag) == 0) {
|
|
||||||
GValue dest = { 0, };
|
|
||||||
GType dest_type = gst_tag_get_type (tagname_gst);
|
|
||||||
|
|
||||||
/* Ensure that any date string is complete */
|
|
||||||
if (dest_type == GST_TYPE_DATE) {
|
|
||||||
guint year = 1901, month = 1, day = 1;
|
|
||||||
|
|
||||||
/* Dates can be yyyy-MM-dd, yyyy-MM or yyyy, but we need
|
|
||||||
* the first type */
|
|
||||||
if (sscanf (value, "%04u-%02u-%02u", &year, &month, &day) != 0) {
|
|
||||||
g_free (value);
|
|
||||||
value = g_strdup_printf ("%04u-%02u-%02u", year, month, day);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_init (&dest, dest_type);
|
|
||||||
if (gst_value_deserialize (&dest, value)) {
|
|
||||||
gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
|
|
||||||
tagname_gst, &dest, NULL);
|
|
||||||
} else {
|
|
||||||
GST_WARNING_OBJECT (parse, "Can't transform tag '%s' with "
|
|
||||||
"value '%s' to target type '%s'", tag, value,
|
|
||||||
g_type_name (dest_type));
|
|
||||||
}
|
|
||||||
g_value_unset (&dest);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (tag);
|
|
||||||
g_free (value);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse,
|
|
||||||
GstEbmlRead * ebml, GstTagList ** p_taglist)
|
|
||||||
{
|
|
||||||
guint32 id;
|
|
||||||
GstFlowReturn ret;
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (parse, ebml, "Tag");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "Tag", 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_SIMPLETAG:
|
|
||||||
ret = gst_matroska_parse_parse_metadata_id_simple_tag (parse, ebml,
|
|
||||||
p_taglist);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"Tag", id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "Tag", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|
||||||
{
|
|
||||||
GstTagList *taglist;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
guint32 id;
|
|
||||||
GList *l;
|
|
||||||
guint64 curpos;
|
|
||||||
|
|
||||||
curpos = gst_ebml_read_get_pos (ebml);
|
|
||||||
|
|
||||||
/* Make sure we don't parse a tags element twice and
|
|
||||||
* post it's tags twice */
|
|
||||||
curpos = gst_ebml_read_get_pos (ebml);
|
|
||||||
for (l = parse->tags_parsed; l; l = l->next) {
|
|
||||||
guint64 *pos = l->data;
|
|
||||||
|
|
||||||
if (*pos == curpos) {
|
|
||||||
GST_DEBUG_OBJECT (parse, "Skipping already parsed Tags at offset %"
|
|
||||||
G_GUINT64_FORMAT, curpos);
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parse->tags_parsed =
|
|
||||||
g_list_prepend (parse->tags_parsed, g_slice_new (guint64));
|
|
||||||
*((guint64 *) parse->tags_parsed->data) = curpos;
|
|
||||||
/* fall-through */
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "Tags", 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_TAG:
|
|
||||||
ret = gst_matroska_parse_parse_metadata_id_tag (parse, ebml, &taglist);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"Tags", id);
|
|
||||||
break;
|
|
||||||
/* FIXME: Use to limit the tags to specific pads */
|
|
||||||
case GST_MATROSKA_ID_TARGETS:
|
|
||||||
ret = gst_ebml_read_skip (ebml);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "Tags", ret);
|
|
||||||
|
|
||||||
gst_matroska_read_common_found_global_tag (&parse->common,
|
|
||||||
GST_ELEMENT_CAST (parse), taglist);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse,
|
|
||||||
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 (parse, ebml, "AttachedFile");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, 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 (parse, "FileDescription can only appear once");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_ebml_read_utf8 (ebml, &id, &description);
|
|
||||||
GST_DEBUG_OBJECT (parse, "FileDescription: %s",
|
|
||||||
GST_STR_NULL (description));
|
|
||||||
break;
|
|
||||||
case GST_MATROSKA_ID_FILENAME:
|
|
||||||
if (filename) {
|
|
||||||
GST_WARNING_OBJECT (parse, "FileName can only appear once");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_ebml_read_utf8 (ebml, &id, &filename);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (parse, "FileName: %s", GST_STR_NULL (filename));
|
|
||||||
break;
|
|
||||||
case GST_MATROSKA_ID_FILEMIMETYPE:
|
|
||||||
if (mimetype) {
|
|
||||||
GST_WARNING_OBJECT (parse, "FileMimeType can only appear once");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_ebml_read_ascii (ebml, &id, &mimetype);
|
|
||||||
GST_DEBUG_OBJECT (parse, "FileMimeType: %s", GST_STR_NULL (mimetype));
|
|
||||||
break;
|
|
||||||
case GST_MATROSKA_ID_FILEDATA:
|
|
||||||
if (data) {
|
|
||||||
GST_WARNING_OBJECT (parse, "FileData can only appear once");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_ebml_read_binary (ebml, &id, &data, &datalen);
|
|
||||||
GST_DEBUG_OBJECT (parse, "FileData of size %" G_GUINT64_FORMAT,
|
|
||||||
datalen);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"AttachedFile", id);
|
|
||||||
break;
|
|
||||||
case GST_MATROSKA_ID_FILEUID:
|
|
||||||
ret = gst_ebml_read_skip (ebml);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (parse, 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 (parse, "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 (parse,
|
|
||||||
"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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_attachments (GstMatroskaParse * parse,
|
|
||||||
GstEbmlRead * ebml)
|
|
||||||
{
|
|
||||||
guint32 id;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
GstTagList *taglist;
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (parse, ebml, "Attachments");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, 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_parse_parse_attached_file (parse, ebml, taglist);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
|
|
||||||
"Attachments", id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_ELEMENT_STOP (parse, ebml, "Attachments", ret);
|
|
||||||
|
|
||||||
if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
|
|
||||||
GST_DEBUG_OBJECT (parse, "Storing attachment tags");
|
|
||||||
gst_matroska_read_common_found_global_tag (&parse->common,
|
|
||||||
GST_ELEMENT_CAST (parse), taglist);
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (parse, "No valid attachments found");
|
|
||||||
gst_tag_list_free (taglist);
|
|
||||||
}
|
|
||||||
|
|
||||||
parse->attachments_parsed = TRUE;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_matroska_parse_parse_chapters (GstMatroskaParse * parse, GstEbmlRead * ebml)
|
|
||||||
{
|
|
||||||
guint32 id;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
|
|
||||||
GST_WARNING_OBJECT (parse, "Parsing of chapters not implemented yet");
|
|
||||||
|
|
||||||
/* TODO: implement parsing of chapters */
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (parse, ebml, "Chapters");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
|
||||||
DEBUG_ELEMENT_STOP (parse, 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 (parse, ebml, "Chapters", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read signed/unsigned "EBML" numbers.
|
* Read signed/unsigned "EBML" numbers.
|
||||||
* Return: number of bytes processed.
|
* Return: number of bytes processed.
|
||||||
|
@ -2461,13 +1871,14 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
||||||
"generating segment starting at %" GST_TIME_FORMAT,
|
"generating segment starting at %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (lace_time));
|
GST_TIME_ARGS (lace_time));
|
||||||
/* pretend we seeked here */
|
/* pretend we seeked here */
|
||||||
gst_segment_set_seek (&parse->segment, parse->segment.rate,
|
gst_segment_set_seek (&parse->common.segment, parse->common.segment.rate,
|
||||||
GST_FORMAT_TIME, 0, GST_SEEK_TYPE_SET, lace_time,
|
GST_FORMAT_TIME, 0, GST_SEEK_TYPE_SET, lace_time,
|
||||||
GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE, NULL);
|
GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE, NULL);
|
||||||
/* now convey our segment notion downstream */
|
/* now convey our segment notion downstream */
|
||||||
gst_matroska_parse_send_event (parse, gst_event_new_new_segment (FALSE,
|
gst_matroska_parse_send_event (parse, gst_event_new_new_segment (FALSE,
|
||||||
parse->segment.rate, parse->segment.format, parse->segment.start,
|
parse->common.segment.rate, parse->common.segment.format,
|
||||||
parse->segment.stop, parse->segment.start));
|
parse->common.segment.start, parse->common.segment.stop,
|
||||||
|
parse->common.segment.start));
|
||||||
parse->need_newsegment = FALSE;
|
parse->need_newsegment = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2509,7 +1920,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
||||||
will instad skip until the next keyframe. */
|
will instad skip until the next keyframe. */
|
||||||
if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
|
if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
|
||||||
stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
|
stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
|
||||||
stream->index_table && parse->segment.rate > 0.0) {
|
stream->index_table && parse->common.segment.rate > 0.0) {
|
||||||
GstMatroskaTrackVideoContext *videocontext =
|
GstMatroskaTrackVideoContext *videocontext =
|
||||||
(GstMatroskaTrackVideoContext *) stream;
|
(GstMatroskaTrackVideoContext *) stream;
|
||||||
GstClockTime earliest_time;
|
GstClockTime earliest_time;
|
||||||
|
@ -2518,7 +1929,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
||||||
GST_OBJECT_LOCK (parse);
|
GST_OBJECT_LOCK (parse);
|
||||||
earliest_time = videocontext->earliest_time;
|
earliest_time = videocontext->earliest_time;
|
||||||
GST_OBJECT_UNLOCK (parse);
|
GST_OBJECT_UNLOCK (parse);
|
||||||
earliest_stream_time = gst_segment_to_position (&parse->segment,
|
earliest_stream_time = gst_segment_to_position (&parse->common.segment,
|
||||||
GST_FORMAT_TIME, earliest_time);
|
GST_FORMAT_TIME, earliest_time);
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
|
if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
|
||||||
|
@ -2566,11 +1977,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
|
||||||
GstClockTime last_stop_end;
|
GstClockTime last_stop_end;
|
||||||
|
|
||||||
/* Check if this stream is after segment stop */
|
/* Check if this stream is after segment stop */
|
||||||
if (GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
|
if (GST_CLOCK_TIME_IS_VALID (parse->common.segment.stop) &&
|
||||||
lace_time >= parse->segment.stop) {
|
lace_time >= parse->common.segment.stop) {
|
||||||
GST_DEBUG_OBJECT (parse,
|
GST_DEBUG_OBJECT (parse,
|
||||||
"Stream %d after segment stop %" GST_TIME_FORMAT, stream->index,
|
"Stream %d after segment stop %" GST_TIME_FORMAT, stream->index,
|
||||||
GST_TIME_ARGS (parse->segment.stop));
|
GST_TIME_ARGS (parse->common.segment.stop));
|
||||||
gst_buffer_unref (sub);
|
gst_buffer_unref (sub);
|
||||||
goto eos;
|
goto eos;
|
||||||
}
|
}
|
||||||
|
@ -3238,8 +2649,9 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case GST_MATROSKA_ID_SEGMENTINFO:
|
case GST_MATROSKA_ID_SEGMENTINFO:
|
||||||
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
||||||
if (!parse->segmentinfo_parsed) {
|
if (!parse->common.segmentinfo_parsed) {
|
||||||
ret = gst_matroska_parse_parse_info (parse, &ebml);
|
ret = gst_matroska_read_common_parse_info (&parse->common,
|
||||||
|
GST_ELEMENT_CAST (parse), &ebml);
|
||||||
}
|
}
|
||||||
gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
|
gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
|
||||||
break;
|
break;
|
||||||
|
@ -3328,19 +2740,21 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_ATTACHMENTS:
|
case GST_MATROSKA_ID_ATTACHMENTS:
|
||||||
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
||||||
if (!parse->attachments_parsed) {
|
if (!parse->common.attachments_parsed) {
|
||||||
ret = gst_matroska_parse_parse_attachments (parse, &ebml);
|
ret = gst_matroska_read_common_parse_attachments (&parse->common,
|
||||||
|
GST_ELEMENT_CAST (parse), &ebml);
|
||||||
}
|
}
|
||||||
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_TAGS:
|
case GST_MATROSKA_ID_TAGS:
|
||||||
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
||||||
ret = gst_matroska_parse_parse_metadata (parse, &ebml);
|
ret = gst_matroska_read_common_parse_metadata (&parse->common,
|
||||||
|
GST_ELEMENT_CAST (parse), &ebml);
|
||||||
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_CHAPTERS:
|
case GST_MATROSKA_ID_CHAPTERS:
|
||||||
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
|
||||||
ret = gst_matroska_parse_parse_chapters (parse, &ebml);
|
ret = gst_matroska_read_common_parse_chapters (&parse->common, &ebml);
|
||||||
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
gst_matroska_parse_output (parse, ebml.buf, FALSE);
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_SEEKHEAD:
|
case GST_MATROSKA_ID_SEEKHEAD:
|
||||||
|
@ -3698,12 +3112,12 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
|
||||||
parse->common.offset = start;
|
parse->common.offset = start;
|
||||||
/* do not know where we are;
|
/* do not know where we are;
|
||||||
* need to come across a cluster and generate newsegment */
|
* need to come across a cluster and generate newsegment */
|
||||||
parse->segment.last_stop = GST_CLOCK_TIME_NONE;
|
parse->common.segment.last_stop = GST_CLOCK_TIME_NONE;
|
||||||
parse->cluster_time = GST_CLOCK_TIME_NONE;
|
parse->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
parse->cluster_offset = 0;
|
parse->cluster_offset = 0;
|
||||||
parse->need_newsegment = TRUE;
|
parse->need_newsegment = TRUE;
|
||||||
/* but keep some of the upstream segment */
|
/* but keep some of the upstream segment */
|
||||||
parse->segment.rate = rate;
|
parse->common.segment.rate = rate;
|
||||||
exit:
|
exit:
|
||||||
/* chain will send initial newsegment after pads have been added,
|
/* chain will send initial newsegment after pads have been added,
|
||||||
* or otherwise come up with one */
|
* or otherwise come up with one */
|
||||||
|
@ -3733,7 +3147,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
|
||||||
gst_matroska_read_common_reset_streams (&parse->common,
|
gst_matroska_read_common_reset_streams (&parse->common,
|
||||||
GST_CLOCK_TIME_NONE, TRUE);
|
GST_CLOCK_TIME_NONE, TRUE);
|
||||||
GST_OBJECT_UNLOCK (parse);
|
GST_OBJECT_UNLOCK (parse);
|
||||||
parse->segment.last_stop = GST_CLOCK_TIME_NONE;
|
parse->common.segment.last_stop = GST_CLOCK_TIME_NONE;
|
||||||
parse->cluster_time = GST_CLOCK_TIME_NONE;
|
parse->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
parse->cluster_offset = 0;
|
parse->cluster_offset = 0;
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
|
@ -60,11 +60,6 @@ typedef struct _GstMatroskaParse {
|
||||||
gboolean pushed_headers;
|
gboolean pushed_headers;
|
||||||
GstClockTime last_timestamp;
|
GstClockTime last_timestamp;
|
||||||
|
|
||||||
/* metadata */
|
|
||||||
gchar *muxing_app;
|
|
||||||
gchar *writing_app;
|
|
||||||
gint64 created;
|
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
//gboolean streaming;
|
//gboolean streaming;
|
||||||
guint level_up;
|
guint level_up;
|
||||||
|
@ -73,13 +68,9 @@ typedef struct _GstMatroskaParse {
|
||||||
|
|
||||||
/* did we parse cues/tracks/segmentinfo already? */
|
/* did we parse cues/tracks/segmentinfo already? */
|
||||||
gboolean tracks_parsed;
|
gboolean tracks_parsed;
|
||||||
gboolean segmentinfo_parsed;
|
|
||||||
gboolean attachments_parsed;
|
|
||||||
GList *tags_parsed;
|
|
||||||
GList *seek_parsed;
|
GList *seek_parsed;
|
||||||
|
|
||||||
/* keeping track of playback position */
|
/* keeping track of playback position */
|
||||||
GstSegment segment;
|
|
||||||
gboolean segment_running;
|
gboolean segment_running;
|
||||||
GstClockTime last_stop_end;
|
GstClockTime last_stop_end;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <gst/tag/tag.h>
|
||||||
|
#include <gst/base/gsttypefindhelper.h>
|
||||||
|
|
||||||
#include "lzo.h"
|
#include "lzo.h"
|
||||||
|
|
||||||
#include "ebml-read.h"
|
#include "ebml-read.h"
|
||||||
|
@ -484,6 +487,242 @@ gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
|
||||||
return gst_ebml_read_skip (ebml);
|
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
|
GstFlowReturn
|
||||||
gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
|
gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
|
||||||
GstEbmlRead * ebml)
|
GstEbmlRead * ebml)
|
||||||
|
@ -953,6 +1192,360 @@ gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_DATEUTC:{
|
||||||
|
gint64 time;
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_date (ebml, &id, &time)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (common, "DateUTC: %" G_GINT64_FORMAT, time);
|
||||||
|
common->created = time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_TITLE:{
|
||||||
|
gchar *text;
|
||||||
|
GstTagList *taglist;
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_utf8 (ebml, &id, &text)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (common, "Title: %s", GST_STR_NULL (text));
|
||||||
|
taglist = gst_tag_list_new ();
|
||||||
|
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text,
|
||||||
|
NULL);
|
||||||
|
gst_matroska_read_common_found_global_tag (common, el, taglist);
|
||||||
|
g_free (text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = gst_matroska_read_common_parse_skip (common, ebml,
|
||||||
|
"SegmentInfo", id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* fall through */
|
||||||
|
case GST_MATROSKA_ID_SEGMENTUID:
|
||||||
|
case GST_MATROSKA_ID_SEGMENTFILENAME:
|
||||||
|
case GST_MATROSKA_ID_PREVUID:
|
||||||
|
case GST_MATROSKA_ID_PREVFILENAME:
|
||||||
|
case GST_MATROSKA_ID_NEXTUID:
|
||||||
|
case GST_MATROSKA_ID_NEXTFILENAME:
|
||||||
|
case GST_MATROSKA_ID_SEGMENTFAMILY:
|
||||||
|
case GST_MATROSKA_ID_CHAPTERTRANSLATE:
|
||||||
|
ret = gst_ebml_read_skip (ebml);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dur_f > 0.0) {
|
||||||
|
GstClockTime dur_u;
|
||||||
|
|
||||||
|
dur_u = gst_gdouble_to_guint64 (dur_f *
|
||||||
|
gst_guint64_to_gdouble (common->time_scale));
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
|
||||||
|
gst_segment_set_duration (&common->segment, GST_FORMAT_TIME, dur_u);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "SegmentInfo", ret);
|
||||||
|
|
||||||
|
common->segmentinfo_parsed = TRUE;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_metadata_id_simple_tag (GstMatroskaReadCommon *
|
||||||
|
common, GstEbmlRead * ebml, GstTagList ** p_taglist)
|
||||||
|
{
|
||||||
|
/* FIXME: check if there are more useful mappings */
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const gchar *matroska_tagname;
|
||||||
|
const gchar *gstreamer_tagname;
|
||||||
|
}
|
||||||
|
tag_conv[] = {
|
||||||
|
{
|
||||||
|
GST_MATROSKA_TAG_ID_TITLE, GST_TAG_TITLE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_ARTIST, GST_TAG_ARTIST}, {
|
||||||
|
GST_MATROSKA_TAG_ID_AUTHOR, GST_TAG_ARTIST}, {
|
||||||
|
GST_MATROSKA_TAG_ID_ALBUM, GST_TAG_ALBUM}, {
|
||||||
|
GST_MATROSKA_TAG_ID_COMMENTS, GST_TAG_COMMENT}, {
|
||||||
|
GST_MATROSKA_TAG_ID_BITSPS, GST_TAG_BITRATE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_BPS, GST_TAG_BITRATE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_ENCODER, GST_TAG_ENCODER}, {
|
||||||
|
GST_MATROSKA_TAG_ID_DATE, GST_TAG_DATE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_ISRC, GST_TAG_ISRC}, {
|
||||||
|
GST_MATROSKA_TAG_ID_COPYRIGHT, GST_TAG_COPYRIGHT}, {
|
||||||
|
GST_MATROSKA_TAG_ID_BPM, GST_TAG_BEATS_PER_MINUTE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_TERMS_OF_USE, GST_TAG_LICENSE}, {
|
||||||
|
GST_MATROSKA_TAG_ID_COMPOSER, GST_TAG_COMPOSER}, {
|
||||||
|
GST_MATROSKA_TAG_ID_LEAD_PERFORMER, GST_TAG_PERFORMER}, {
|
||||||
|
GST_MATROSKA_TAG_ID_GENRE, GST_TAG_GENRE}
|
||||||
|
};
|
||||||
|
GstFlowReturn ret;
|
||||||
|
guint32 id;
|
||||||
|
gchar *value = NULL;
|
||||||
|
gchar *tag = NULL;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "SimpleTag");
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", 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_TAGNAME:
|
||||||
|
g_free (tag);
|
||||||
|
tag = NULL;
|
||||||
|
ret = gst_ebml_read_ascii (ebml, &id, &tag);
|
||||||
|
GST_DEBUG_OBJECT (common, "TagName: %s", GST_STR_NULL (tag));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_TAGSTRING:
|
||||||
|
g_free (value);
|
||||||
|
value = NULL;
|
||||||
|
ret = gst_ebml_read_utf8 (ebml, &id, &value);
|
||||||
|
GST_DEBUG_OBJECT (common, "TagString: %s", GST_STR_NULL (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = gst_matroska_read_common_parse_skip (common, ebml, "SimpleTag",
|
||||||
|
id);
|
||||||
|
break;
|
||||||
|
/* fall-through */
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_TAGLANGUAGE:
|
||||||
|
case GST_MATROSKA_ID_TAGDEFAULT:
|
||||||
|
case GST_MATROSKA_ID_TAGBINARY:
|
||||||
|
ret = gst_ebml_read_skip (ebml);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "SimpleTag", ret);
|
||||||
|
|
||||||
|
if (tag && value) {
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (tag_conv); i++) {
|
||||||
|
const gchar *tagname_gst = tag_conv[i].gstreamer_tagname;
|
||||||
|
|
||||||
|
const gchar *tagname_mkv = tag_conv[i].matroska_tagname;
|
||||||
|
|
||||||
|
if (strcmp (tagname_mkv, tag) == 0) {
|
||||||
|
GValue dest = { 0, };
|
||||||
|
GType dest_type = gst_tag_get_type (tagname_gst);
|
||||||
|
|
||||||
|
/* Ensure that any date string is complete */
|
||||||
|
if (dest_type == GST_TYPE_DATE) {
|
||||||
|
guint year = 1901, month = 1, day = 1;
|
||||||
|
|
||||||
|
/* Dates can be yyyy-MM-dd, yyyy-MM or yyyy, but we need
|
||||||
|
* the first type */
|
||||||
|
if (sscanf (value, "%04u-%02u-%02u", &year, &month, &day) != 0) {
|
||||||
|
g_free (value);
|
||||||
|
value = g_strdup_printf ("%04u-%02u-%02u", year, month, day);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_value_init (&dest, dest_type);
|
||||||
|
if (gst_value_deserialize (&dest, value)) {
|
||||||
|
gst_tag_list_add_values (*p_taglist, GST_TAG_MERGE_APPEND,
|
||||||
|
tagname_gst, &dest, NULL);
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (common, "Can't transform tag '%s' with "
|
||||||
|
"value '%s' to target type '%s'", tag, value,
|
||||||
|
g_type_name (dest_type));
|
||||||
|
}
|
||||||
|
g_value_unset (&dest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (tag);
|
||||||
|
g_free (value);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml, GstTagList ** p_taglist)
|
||||||
|
{
|
||||||
|
guint32 id;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "Tag");
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "Tag", 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_SIMPLETAG:
|
||||||
|
ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
|
||||||
|
ebml, p_taglist);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = gst_matroska_read_common_parse_skip (common, ebml, "Tag", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
|
||||||
|
GstElement * el, GstEbmlRead * ebml)
|
||||||
|
{
|
||||||
|
GstTagList *taglist;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
guint32 id;
|
||||||
|
GList *l;
|
||||||
|
guint64 curpos;
|
||||||
|
|
||||||
|
curpos = gst_ebml_read_get_pos (ebml);
|
||||||
|
|
||||||
|
/* Make sure we don't parse a tags element twice and
|
||||||
|
* post it's tags twice */
|
||||||
|
curpos = gst_ebml_read_get_pos (ebml);
|
||||||
|
for (l = common->tags_parsed; l; l = l->next) {
|
||||||
|
guint64 *pos = l->data;
|
||||||
|
|
||||||
|
if (*pos == curpos) {
|
||||||
|
GST_DEBUG_OBJECT (common, "Skipping already parsed Tags at offset %"
|
||||||
|
G_GUINT64_FORMAT, curpos);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
common->tags_parsed =
|
||||||
|
g_list_prepend (common->tags_parsed, g_slice_new (guint64));
|
||||||
|
*((guint64 *) common->tags_parsed->data) = curpos;
|
||||||
|
/* fall-through */
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "Tags", 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_TAG:
|
||||||
|
ret = gst_matroska_read_common_parse_metadata_id_tag (common, ebml,
|
||||||
|
&taglist);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = gst_matroska_read_common_parse_skip (common, ebml, "Tags", id);
|
||||||
|
break;
|
||||||
|
/* FIXME: Use to limit the tags to specific pads */
|
||||||
|
case GST_MATROSKA_ID_TARGETS:
|
||||||
|
ret = gst_ebml_read_skip (ebml);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
|
||||||
|
|
||||||
|
gst_matroska_read_common_found_global_tag (common, el, taglist);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const guint8 *
|
static const guint8 *
|
||||||
gst_matroska_read_common_peek_adapter (GstMatroskaReadCommon * common, guint
|
gst_matroska_read_common_peek_adapter (GstMatroskaReadCommon * common, guint
|
||||||
peek)
|
peek)
|
||||||
|
|
|
@ -49,11 +49,19 @@ typedef struct _GstMatroskaReadCommon {
|
||||||
GPtrArray *src;
|
GPtrArray *src;
|
||||||
guint num_streams;
|
guint num_streams;
|
||||||
|
|
||||||
|
/* metadata */
|
||||||
|
gchar *muxing_app;
|
||||||
|
gchar *writing_app;
|
||||||
|
gint64 created;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
GstMatroskaReadState state;
|
GstMatroskaReadState state;
|
||||||
|
|
||||||
/* did we parse cues/tracks/segmentinfo already? */
|
/* did we parse cues/tracks/segmentinfo already? */
|
||||||
gboolean index_parsed;
|
gboolean index_parsed;
|
||||||
|
gboolean segmentinfo_parsed;
|
||||||
|
gboolean attachments_parsed;
|
||||||
|
GList *tags_parsed;
|
||||||
|
|
||||||
/* start-of-segment */
|
/* start-of-segment */
|
||||||
guint64 ebml_segment_start;
|
guint64 ebml_segment_start;
|
||||||
|
@ -64,6 +72,9 @@ typedef struct _GstMatroskaReadCommon {
|
||||||
/* timescale in the file */
|
/* timescale in the file */
|
||||||
guint64 time_scale;
|
guint64 time_scale;
|
||||||
|
|
||||||
|
/* keeping track of playback position */
|
||||||
|
GstSegment segment;
|
||||||
|
|
||||||
GstTagList *global_tags;
|
GstTagList *global_tags;
|
||||||
|
|
||||||
/* pull mode caching */
|
/* pull mode caching */
|
||||||
|
@ -91,8 +102,16 @@ GstMatroskaTrackContext * gst_matroska_read_common_get_seek_track (
|
||||||
GstMatroskaReadCommon * common, GstMatroskaTrackContext * track);
|
GstMatroskaReadCommon * common, GstMatroskaTrackContext * track);
|
||||||
GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
|
GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
|
||||||
common, GstEbmlRead * ebml);
|
common, GstEbmlRead * ebml);
|
||||||
|
GstFlowReturn gst_matroska_read_common_parse_info (GstMatroskaReadCommon *
|
||||||
|
common, GstElement * el, GstEbmlRead * ebml);
|
||||||
|
GstFlowReturn gst_matroska_read_common_parse_attachments (
|
||||||
|
GstMatroskaReadCommon * common, GstElement * el, GstEbmlRead * ebml);
|
||||||
|
GstFlowReturn gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon *
|
||||||
|
common, GstEbmlRead * ebml);
|
||||||
GstFlowReturn gst_matroska_read_common_parse_header (GstMatroskaReadCommon *
|
GstFlowReturn gst_matroska_read_common_parse_header (GstMatroskaReadCommon *
|
||||||
common, GstEbmlRead * ebml);
|
common, GstEbmlRead * ebml);
|
||||||
|
GstFlowReturn gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon *
|
||||||
|
common, GstElement * el, GstEbmlRead * ebml);
|
||||||
GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
|
GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
|
||||||
common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
|
common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
|
||||||
GstFlowReturn gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon *
|
GstFlowReturn gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon *
|
||||||
|
|
|
@ -6434,6 +6434,8 @@ gst_rtspsrc_thread (GstRTSPSrc * src)
|
||||||
else if (src->task)
|
else if (src->task)
|
||||||
gst_task_pause (src->task);
|
gst_task_pause (src->task);
|
||||||
}
|
}
|
||||||
|
/* reset waiting */
|
||||||
|
src->waiting = FALSE;
|
||||||
GST_OBJECT_UNLOCK (src);
|
GST_OBJECT_UNLOCK (src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue