else
check-torture:
true
- build-checks:
- true
endif
-win32-update:
- cp $(top_builddir)/win32/common/config.h-new \
- $(top_srcdir)/win32/common/config.h
-
include $(top_srcdir)/common/coverage/lcov.mak
# cruft: plugins that have been merged or moved or renamed
AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes")
AM_CONDITIONAL(HAVE_GTK_X11, test "x$HAVE_GTK_X11" = "xyes")
+ AC_ARG_ENABLE(pcmdump, AC_HELP_STRING([--enable-pcmdump], [pcm dump]),
+ [
+ case "${enableval}" in
+ yes) PCM_DUMP_ENABLE=yes ;;
+ no) PCM_DUMP_ENABLE=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-pcmdump) ;;
+ esac
+ ],
+ [PCM_DUMP_ENABLE=no])
+ AM_CONDITIONAL([PCM_DUMP_ENABLE], [test "x$PCM_DUMP_ENABLE" = "xyes"])
+
+ if test "x$PCM_DUMP_ENABLE" = "xyes"; then
+ PKG_CHECK_MODULES(VCONF, vconf)
+ AC_SUBST(VCONF_CFLAGS)
+ AC_SUBST(VCONF_LIBS)
+ fi
+
+dnl Check for -Bsymbolic-functions linker flag used to avoid
+dnl intra-library PLT jumps, if available.
+AC_ARG_ENABLE(Bsymbolic,
+ [AS_HELP_STRING([--disable-Bsymbolic],[avoid linking with -Bsymbolic])],,
+ [SAVED_LDFLAGS="${LDFLAGS}" SAVED_LIBS="${LIBS}"
+ AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
+ LDFLAGS=-Wl,-Bsymbolic-functions
+ LIBS=
+ AC_TRY_LINK([], [return 0],
+ AC_MSG_RESULT(yes)
+ enable_Bsymbolic=yes,
+ AC_MSG_RESULT(no)
+ enable_Bsymbolic=no)
+ LDFLAGS="${SAVED_LDFLAGS}" LIBS="${SAVED_LIBS}"])
+
dnl *** set variables based on configure arguments ***
dnl set license and copyright notice
dnl *** soup ***
translit(dnm, m, l) AM_CONDITIONAL(USE_SOUP, true)
AG_GST_CHECK_FEATURE(SOUP, [soup http client plugin (2.4)], souphttpsrc, [
- PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.48, [HAVE_SOUP="yes"], [HAVE_SOUP="no"])
- PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.40, [HAVE_SOUP="yes"], [HAVE_SOUP="no"])
++ PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.46, [HAVE_SOUP="yes"], [HAVE_SOUP="no"])
AC_SUBST(SOUP_CFLAGS)
AC_SUBST(SOUP_LIBS)
])
pulsedeviceprovider.c \
pulseutil.c
-libgstpulse_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(PULSE_CFLAGS)
-libgstpulse_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
+libgstpulseaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(PULSE_CFLAGS)
+libgstpulseaudio_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
-lgstpbutils-$(GST_API_VERSION) \
$(GST_BASE_LIBS) $(GST_LIBS) $(PULSE_LIBS)
-libgstpulse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstpulse_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+libgstpulseaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstpulseaudio_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
-libgstpulse_la_CFLAGS += $(VCONF_CFLAGS) -DPCM_DUMP_ENABLE
-libgstpulse_la_LIBADD += $(VCONF_LIBS)
+ if PCM_DUMP_ENABLE
++libgstpulseaudio_la_CFLAGS += $(VCONF_CFLAGS) -DPCM_DUMP_ENABLE
++libgstpulseaudio_la_LIBADD += $(VCONF_LIBS)
+ endif
+
noinst_HEADERS = \
pulsesink.h \
pulsesrc.h \
#define DEFAULT_VOLUME 1.0
#define DEFAULT_MUTE FALSE
#define MAX_VOLUME 10.0
+ #ifdef __TIZEN__
+ #define DEFAULT_AUDIO_LATENCY "mid"
+ #endif /* __TIZEN__ */
++/* See the pulsesink code for notes on how we interact with the PA mainloop
++ * thread. */
/* See the pulsesink code for notes on how we interact with the PA mainloop
* thread. */
-plugin_LTLIBRARIES = libgstsouphttpsrc.la
+plugin_LTLIBRARIES = libgstsoup.la
-libgstsouphttpsrc_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsouputils.c gstsoup.c
+libgstsoup_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsouputils.c gstsoup.c
-libgstsouphttpsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+libgstsoup_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_CFLAGS) $(SOUP_CFLAGS) \
- -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_48 \
- -DSOUP_VERSION_MAX_ALLOWED=SOUP_DEPRECATED_IN_2_48
- -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_26 \
- -DSOUP_VERSION_MAX_ALLOWED=SOUP_DEPRECATED_IN_2_26
-libgstsouphttpsrc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ $(GST_BASE_LIBS) $(SOUP_LIBS)
-libgstsouphttpsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstsouphttpsrc_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
++ -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_46 \
++ -DSOUP_VERSION_MAX_ALLOWED=SOUP_DEPRECATED_IN_2_46
+libgstsoup_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_API_VERSION@ $(GST_BASE_LIBS) $(SOUP_LIBS)
+libgstsoup_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstsoup_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h gstsouputils.h
src->content_size = 0;
src->have_body = FALSE;
- src->ret = GST_FLOW_OK;
+ src->reduce_blocksize_count = 0;
+ src->increase_blocksize_count = 0;
+
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ if (src->dash_oldest_segment) {
+ g_free (src->dash_oldest_segment);
+ src->dash_oldest_segment = NULL;
+ }
+ if (src->dash_newest_segment) {
+ g_free (src->dash_newest_segment);
+ src->dash_newest_segment = NULL;
+ }
+ #endif
++
+ g_cancellable_reset (src->cancellable);
+ if (src->input_stream) {
+ g_object_unref (src->input_stream);
+ src->input_stream = NULL;
+ }
gst_caps_replace (&src->src_caps, NULL);
g_free (src->iradio_name);
src->ssl_strict = DEFAULT_SSL_STRICT;
src->ssl_use_system_ca_file = DEFAULT_SSL_USE_SYSTEM_CA_FILE;
src->tls_database = DEFAULT_TLS_DATABASE;
+ src->tls_interaction = DEFAULT_TLS_INTERACTION;
src->max_retries = DEFAULT_RETRIES;
src->method = DEFAULT_SOUP_METHOD;
+ src->minimum_blocksize = gst_base_src_get_blocksize (GST_BASE_SRC_CAST (src));
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ src->dash_oldest_segment = NULL;
+ src->dash_newest_segment = NULL;
+ #endif
proxy = g_getenv ("http_proxy");
if (!gst_soup_http_src_set_proxy (src, proxy)) {
GST_WARNING_OBJECT (src,
gint rc;
soup_message_headers_remove (src->msg->request_headers, "Range");
- if (offset || stop_offset != -1) {
+
+ /* This changes are needed to enable Seekable Contents from server.
+ We have observed that , for few specific networks ( VODAFONE ) , without theabove headers ,
+ Youtube is sending non-seekable contents to the Client. */
+ #ifndef TIZEN_FEATURE_SOUP_MODIFICATION
+ if (offset || stop_offset != -1)
+ #endif
+ {
if (stop_offset != -1) {
+ g_assert (offset != stop_offset);
+
rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-%"
- G_GUINT64_FORMAT, offset, stop_offset);
+ G_GUINT64_FORMAT, offset, (stop_offset > 0) ? stop_offset - 1 :
+ stop_offset);
} else {
rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-",
- offset);
+ offset);
}
if (rc > sizeof (buf) || rc < 0)
return FALSE;
GST_DEBUG_OBJECT (src, "Creating session");
if (src->proxy == NULL) {
src->session =
- soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
- src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
- SOUP_SESSION_TIMEOUT, src->timeout,
- SOUP_SESSION_SSL_STRICT, src->ssl_strict,
- SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
- NULL);
+ soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
+ src->user_agent, SOUP_SESSION_TIMEOUT, src->timeout,
- SOUP_SESSION_SSL_STRICT, src->ssl_strict,
- SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
++ SOUP_SESSION_SSL_STRICT, src->ssl_strict, NULL);
++// SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
} else {
src->session =
- soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
- src->context, SOUP_SESSION_PROXY_URI, src->proxy,
+ soup_session_new_with_options (SOUP_SESSION_PROXY_URI, src->proxy,
SOUP_SESSION_TIMEOUT, src->timeout,
SOUP_SESSION_SSL_STRICT, src->ssl_strict,
- SOUP_SESSION_USER_AGENT, src->user_agent,
- SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+ SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
++// SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
}
if (!src->session) {
{
GST_DEBUG_OBJECT (src, "Closing session");
- if (src->loop)
- g_main_loop_quit (src->loop);
-
g_mutex_lock (&src->mutex);
+ if (src->msg) {
+ soup_session_cancel_message (src->session, src->msg, SOUP_STATUS_CANCELLED);
+ g_object_unref (src->msg);
+ src->msg = NULL;
+ }
+
if (src->session) {
- soup_session_abort (src->session); /* This unrefs the message. */
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ /* When Playback is ongoing and Browser is moved to background ( Pressing Menu or Home Key ), The Session gets destroyed.
+ But the cookie_jar property remains unfreed. This results in garbage pointer and causes crash.
+ Removing the cookie_jar feature during close session of browser to handle the issue. */
+ GST_DEBUG_OBJECT (src, "Removing Cookie Jar instance");
+ soup_session_remove_feature_by_type(src->session, SOUP_TYPE_COOKIE_JAR);
+ src->cookie_jar = NULL;
+ #endif
+ soup_session_abort (src->session);
g_object_unref (src->session);
src->session = NULL;
- src->msg = NULL;
- }
- if (src->loop) {
-#ifdef LIBSOUP_DOES_NOT_STEAL_OUR_CONTEXT
- GSource *idle_source;
-
- /* Iterating the main context to give GIO cancellables a chance
- * to initiate cleanups. Wihout this, resources allocated by
- * libsoup for the connection are not released and socket fd is
- * leaked. */
- idle_source = g_idle_source_new ();
- /* Suppressing "idle souce without callback" warning */
- g_source_set_callback (idle_source, dummy_idle_cb, NULL, NULL);
- g_source_set_priority (idle_source, G_PRIORITY_LOW);
- g_source_attach (idle_source, src->context);
- /* Acquiring the context. Idle source guarantees that we'll not block. */
- g_main_context_push_thread_default (src->context);
- g_main_context_iteration (src->context, TRUE);
- /* Ensuring that there's no unhandled pending events left. */
- while (g_main_context_iteration (src->context, FALSE));
- g_main_context_pop_thread_default (src->context);
- g_source_unref (idle_source);
-#endif
-
- g_main_loop_unref (src->loop);
- g_main_context_unref (src->context);
- src->loop = NULL;
- src->context = NULL;
}
g_mutex_unlock (&src->mutex);
}
}
}
-static void
-gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ static void
+ gst_soup_http_src_headers_foreach (const gchar * name, const gchar * val,
+ gpointer src)
+ {
+ GST_INFO_OBJECT (src, " %s: %s", name, val);
+
+ if (g_ascii_strcasecmp (name, "Set-Cookie") == 0)
+ {
+ if (val)
+ {
+ gboolean bret = FALSE;
+ GstStructure *s = NULL;
+ GstSoupHTTPSrc * tmp = src;
+ SoupURI *uri;
+
+ uri = soup_uri_new (tmp->location);
+
+ /* post current bandwith & uri to application */
+ s = gst_structure_new ("cookies",
+ "updated-cookie", G_TYPE_STRING, val,
+ "updated-url", G_TYPE_STRING, tmp->location, NULL);
+ bret = gst_element_post_message (GST_ELEMENT_CAST (src), gst_message_new_element (GST_OBJECT_CAST (src), s));
+ soup_cookie_jar_set_cookie (tmp->cookie_jar, uri, val);
+ soup_uri_free (uri);
+
+ GST_INFO_OBJECT (src, "request url [%s], posted cookies [%s] msg and returned = %d", tmp->location, val, bret);
+ }
+ }
+ else if (g_ascii_strcasecmp (name, "Dash-Oldest-Segment") == 0)
+ {
+ if (val)
+ {
+ GstSoupHTTPSrc * tmp = src;
+ tmp->dash_oldest_segment = g_strdup (val);
+ GST_INFO_OBJECT (src, "Dash-Oldest-Segment set as %s ", tmp->dash_oldest_segment);
+ }
+ }
+ else if (g_ascii_strcasecmp (name, "Dash-Newest-Segment") == 0)
+ {
+ if (val)
+ {
+ GstSoupHTTPSrc * tmp = src;
+ tmp->dash_newest_segment = g_strdup (val);
+ GST_INFO_OBJECT (src, "Dash-Newest-Segment set as %s ", tmp->dash_newest_segment);
+ }
+ }
+ }
+ #endif
+
+static GstFlowReturn
+gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
{
const char *value;
GstTagList *tag_list;
GstEvent *http_headers_event;
GstStructure *http_headers, *headers;
const gchar *accept_ranges;
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ gint64 start = 0, stop = 0, total = 0;
+ #endif
- GST_INFO_OBJECT (src, "got headers");
-
+ GST_INFO_OBJECT (src, "got headers : %d", msg->status_code);
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ soup_message_headers_foreach (msg->response_headers,
+ gst_soup_http_src_headers_foreach, src);
+ #endif
if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
- src->proxy_id && src->proxy_pw)
- return;
-
- if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
- src->redirection_uri = g_strdup (soup_message_headers_get_one
- (msg->response_headers, "Location"));
- src->redirection_permanent =
- (msg->status_code == SOUP_STATUS_MOVED_PERMANENTLY);
- GST_DEBUG_OBJECT (src, "%u redirect to \"%s\" (permanent %d)",
- msg->status_code, src->redirection_uri, src->redirection_permanent);
- return;
+ src->proxy_id && src->proxy_pw) {
+ /* wait for authenticate callback */
+ return GST_FLOW_OK;
}
- if (msg->status_code == SOUP_STATUS_UNAUTHORIZED)
- return;
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ /* force an error */
+ return gst_soup_http_src_parse_status (msg, src);
+ }
- src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING;
src->got_headers = TRUE;
+ g_cond_broadcast (&src->have_headers_cond);
http_headers = gst_structure_new_empty ("http-headers");
gst_structure_set (http_headers, "uri", G_TYPE_STRING, src->location, NULL);
/* when content_size is unknown and we have just finished receiving
* a body message, requests that go beyond the content limits will result
* in an error. Here we convert those to EOS */
- src->ret = GST_FLOW_EOS;
- return;
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ if (msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE &&
+ ((src->have_body && !src->have_size) ||
+ (src->have_size && src->request_position >= src->content_size))) {
+ GST_DEBUG_OBJECT (src, "Requested range out of limits and received full "
+ "body, returning EOS");
++ return GST_FLOW_EOS;
+ }
+ #else
if (msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE &&
src->have_body && !src->have_size) {
GST_DEBUG_OBJECT (src, "Requested range out of limits and received full "
"body, returning EOS");
- src->ret = GST_FLOW_EOS;
- return;
+ return GST_FLOW_EOS;
}
+ #endif
/* FIXME: reason_phrase is not translated and not suitable for user
* error dialog according to libsoup documentation.
*cookie);
}
}
+ #endif
- src->retry = FALSE;
-
- g_signal_connect (src->msg, "got_headers",
- G_CALLBACK (gst_soup_http_src_got_headers_cb), src);
- g_signal_connect (src->msg, "got_body",
- G_CALLBACK (gst_soup_http_src_got_body_cb), src);
- g_signal_connect (src->msg, "finished",
- G_CALLBACK (gst_soup_http_src_finished_cb), src);
- g_signal_connect (src->msg, "got_chunk",
- G_CALLBACK (gst_soup_http_src_got_chunk_cb), src);
soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
(src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));
- soup_message_set_chunk_allocator (src->msg,
- gst_soup_http_src_chunk_allocator, src, NULL);
+
+ if (src->automatic_redirect) {
+ g_signal_connect (src->msg, "restarted",
+ G_CALLBACK (gst_soup_http_src_restarted_cb), src);
+ }
+
gst_soup_http_src_add_range_header (src, src->request_position,
src->stop_position);
if (!gst_soup_http_src_build_message (src, method)) {
return GST_FLOW_ERROR;
}
+ }
- src->ret = GST_FLOW_CUSTOM_ERROR;
- src->outbuf = outbuf;
- do {
- if (src->interrupted) {
- GST_INFO_OBJECT (src, "interrupted");
- src->ret = GST_FLOW_FLUSHING;
- break;
- }
- if (src->retry) {
- GST_INFO_OBJECT (src, "Reconnecting");
- if (!gst_soup_http_src_build_message (src, method)) {
- return GST_FLOW_ERROR;
- }
- src->retry = FALSE;
- continue;
+ if (g_cancellable_is_cancelled (src->cancellable)) {
+ GST_INFO_OBJECT (src, "interrupted");
+ return GST_FLOW_FLUSHING;
+ }
+
+ ret = gst_soup_http_src_send_message (src);
+
+ /* Check if Range header was respected. */
++#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
++ if (ret == GST_FLOW_OK && src->request_position > 0 &&
++ (src->msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) &&
++ (src->request_position < src->content_size)) {
++#else
+ if (ret == GST_FLOW_OK && src->request_position > 0 &&
+ src->msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) {
++#endif
+ src->seekable = FALSE;
+ GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, SEEK,
+ (_("Server does not support seeking.")),
+ ("Server does not accept Range HTTP header, URL: %s, Redirect to: %s",
+ src->location, GST_STR_NULL (src->redirection_uri)),
+ ("http-status-code", G_TYPE_UINT, src->msg->status_code,
+ "http-redirection-uri", G_TYPE_STRING,
+ GST_STR_NULL (src->redirection_uri), NULL));
+ ret = GST_FLOW_ERROR;
+ }
+
+ return ret;
+}
+
+/*
+ * Check if the bytes_read is above a certain threshold of the blocksize, if
+ * that happens a few times in a row, increase the blocksize; Do the same in
+ * the opposite direction to reduce the blocksize.
+ */
+static void
+gst_soup_http_src_check_update_blocksize (GstSoupHTTPSrc * src,
+ gint64 bytes_read)
+{
+ guint blocksize = gst_base_src_get_blocksize (GST_BASE_SRC_CAST (src));
+
+ GST_LOG_OBJECT (src, "Checking to update blocksize. Read:%" G_GINT64_FORMAT
+ " blocksize:%u", bytes_read, blocksize);
+
+ if (bytes_read >= blocksize * GROW_BLOCKSIZE_LIMIT) {
+ src->reduce_blocksize_count = 0;
+ src->increase_blocksize_count++;
+
+ if (src->increase_blocksize_count >= GROW_BLOCKSIZE_COUNT) {
+ blocksize *= GROW_BLOCKSIZE_FACTOR;
+ GST_DEBUG_OBJECT (src, "Increased blocksize to %u", blocksize);
+ gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src), blocksize);
+ src->increase_blocksize_count = 0;
}
- if (!src->msg) {
- GST_DEBUG_OBJECT (src, "EOS reached");
- break;
+ } else if (bytes_read < blocksize * REDUCE_BLOCKSIZE_LIMIT) {
+ src->reduce_blocksize_count++;
+ src->increase_blocksize_count = 0;
+
+ if (src->reduce_blocksize_count >= REDUCE_BLOCKSIZE_COUNT) {
+ blocksize *= REDUCE_BLOCKSIZE_FACTOR;
+ blocksize = MAX (blocksize, src->minimum_blocksize);
+ GST_DEBUG_OBJECT (src, "Decreased blocksize to %u", blocksize);
+ gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src), blocksize);
+ src->reduce_blocksize_count = 0;
}
+ } else {
+ src->reduce_blocksize_count = src->increase_blocksize_count = 0;
+ }
+}
- switch (src->session_io_status) {
- case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE:
- GST_INFO_OBJECT (src, "Queueing connection request");
- gst_soup_http_src_queue_message (src);
- break;
- case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED:
- break;
- case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING:
- gst_soup_http_src_session_unpause_message (src);
- break;
- case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED:
- /* Impossible. */
- break;
- }
+static void
+gst_soup_http_src_update_position (GstSoupHTTPSrc * src, gint64 bytes_read)
+{
+ GstBaseSrc *basesrc = GST_BASE_SRC_CAST (src);
+ guint64 new_position;
- if (src->ret == GST_FLOW_CUSTOM_ERROR) {
- g_main_context_push_thread_default (src->context);
- g_main_loop_run (src->loop);
- g_main_context_pop_thread_default (src->context);
+ new_position = src->read_position + bytes_read;
+ if (G_LIKELY (src->request_position == src->read_position))
+ src->request_position = new_position;
+ src->read_position = new_position;
+
+ if (src->have_size) {
+ if (new_position > src->content_size) {
+ GST_DEBUG_OBJECT (src, "Got position previous estimated content size "
+ "(%" G_GINT64_FORMAT " > %" G_GINT64_FORMAT ")", new_position,
+ src->content_size);
+ src->content_size = new_position;
+ basesrc->segment.duration = src->content_size;
+ gst_element_post_message (GST_ELEMENT (src),
+ gst_message_new_duration_changed (GST_OBJECT (src)));
+ } else if (new_position == src->content_size) {
+ GST_DEBUG_OBJECT (src, "We're EOS now");
}
+ }
+}
- } while (src->ret == GST_FLOW_CUSTOM_ERROR);
-
- /* Let the request finish if we had a stop position and are there */
- if (src->ret == GST_FLOW_OK && src->stop_position != -1
- && src->read_position >= src->stop_position) {
- src->outbuf = NULL;
- gst_soup_http_src_session_unpause_message (src);
- g_main_context_push_thread_default (src->context);
- g_main_loop_run (src->loop);
- g_main_context_pop_thread_default (src->context);
-
- g_cond_signal (&src->request_finished_cond);
- /* Return OK unconditionally here, src->ret will
- * be most likely be EOS now but we want to
- * consume the buffer we got above */
- return GST_FLOW_OK;
+static GstFlowReturn
+gst_soup_http_src_read_buffer (GstSoupHTTPSrc * src, GstBuffer ** outbuf)
+{
+ gssize read_bytes;
+ GstMapInfo mapinfo;
+ GstBaseSrc *bsrc;
+ GstFlowReturn ret;
+
+ bsrc = GST_BASE_SRC_CAST (src);
+
+ *outbuf = gst_soup_http_src_alloc_buffer (src);
+ if (!*outbuf) {
+ GST_WARNING_OBJECT (src, "Failed to allocate buffer");
+ return GST_FLOW_ERROR;
}
- if (src->ret == GST_FLOW_CUSTOM_ERROR)
- src->ret = GST_FLOW_EOS;
- g_cond_signal (&src->request_finished_cond);
+ if (!gst_buffer_map (*outbuf, &mapinfo, GST_MAP_WRITE)) {
+ GST_WARNING_OBJECT (src, "Failed to map buffer");
+ return GST_FLOW_ERROR;
+ }
- /* basesrc assumes that we don't return a buffer if
- * something else than OK is returned. It will just
- * leak any buffer we might accidentially provide
- * here.
- *
- * This can potentially happen during flushing.
- */
- if (src->ret != GST_FLOW_OK && outbuf && *outbuf) {
+ read_bytes =
+ g_input_stream_read (src->input_stream, mapinfo.data, mapinfo.size,
+ src->cancellable, NULL);
+ GST_DEBUG_OBJECT (src, "Read %" G_GSSIZE_FORMAT " bytes from http input",
+ read_bytes);
+
+ g_mutex_lock (&src->mutex);
+ if (g_cancellable_is_cancelled (src->cancellable)) {
+ gst_buffer_unmap (*outbuf, &mapinfo);
gst_buffer_unref (*outbuf);
- *outbuf = NULL;
+ g_mutex_unlock (&src->mutex);
+ return GST_FLOW_FLUSHING;
+ }
+
+ gst_buffer_unmap (*outbuf, &mapinfo);
+ if (read_bytes > 0) {
+ gst_buffer_set_size (*outbuf, read_bytes);
+ GST_BUFFER_OFFSET (*outbuf) = bsrc->segment.position;
+ ret = GST_FLOW_OK;
+ gst_soup_http_src_update_position (src, read_bytes);
+
+ /* Got some data, reset retry counter */
+ src->retry_count = 0;
+
+ gst_soup_http_src_check_update_blocksize (src, read_bytes);
+
+ /* If we're at the end of a range request, read again to let libsoup
+ * finalize the request. This allows to reuse the connection again later,
+ * otherwise we would have to cancel the message and close the connection
+ */
+ if (bsrc->segment.stop != -1
+ && bsrc->segment.position + read_bytes >= bsrc->segment.stop) {
+ guint8 tmp[128];
+
+ g_object_unref (src->msg);
+ src->msg = NULL;
+ src->have_body = TRUE;
+
+ /* This should return immediately as we're at the end of the range */
+ read_bytes =
+ g_input_stream_read (src->input_stream, tmp, sizeof (tmp),
+ src->cancellable, NULL);
+ if (read_bytes > 0)
+ GST_ERROR_OBJECT (src,
+ "Read %" G_GSIZE_FORMAT " bytes after end of range", read_bytes);
+ }
+ } else {
+ gst_buffer_unref (*outbuf);
+ if (read_bytes < 0 ||
+ (src->have_size && src->read_position < src->content_size)) {
+ /* Maybe the server disconnected, retry */
+ ret = GST_FLOW_CUSTOM_ERROR;
+ } else {
+ g_object_unref (src->msg);
+ src->msg = NULL;
+ ret = GST_FLOW_EOS;
+ src->have_body = TRUE;
+ }
}
+ g_mutex_unlock (&src->mutex);
- return src->ret;
+ return ret;
}
static GstFlowReturn
guint timeout;
GMutex mutex;
- GCond request_finished_cond;
+ GCond have_headers_cond;
GstEvent *http_headers_event;
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+ gchar *dash_oldest_segment;
+ gchar *dash_newest_segment;
+ #endif
};
struct _GstSoupHTTPSrcClass {
headers prepended during raw to ADTS
conversion */
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION /* to get more accurate duration */
+ #define AAC_MAX_ESTIMATE_DURATION_BUF (1024 * 1024) /* use first 1 Mbyte */
+ #define AAC_SAMPLE_PER_FRAME 1024
+
+ #define AAC_MAX_PULL_RANGE_BUF (1 * 1024 * 1024) /* 1 MByte */
+ #define AAC_LARGE_FILE_SIZE (2 * 1024 * 1024) /* 2 MByte */
+ #define gst_aac_parse_parent_class parent_class
+ #endif
+
#define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec)
-static const gint loas_sample_rate_table[32] = {
+static const gint loas_sample_rate_table[16] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_aac_parse_pre_push_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
+static gboolean gst_aac_parse_src_event (GstBaseParse * parse,
+ GstEvent * event);
+
+static gboolean gst_aac_parse_read_audio_specific_config (GstAacParse *
+ aacparse, GstBitReader * br, gint * object_type, gint * sample_rate,
+ gint * channels, gint * frame_samples);
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ static guint gst_aac_parse_adts_get_fast_frame_len (const guint8 * data);
+ static gboolean gst_aac_parse_src_eventfunc (GstBaseParse * parse,
+ GstEvent * event);
+ /* make full aac(adts) index table when seek */
+ static gboolean gst_aac_parse_adts_src_eventfunc (GstBaseParse * parse,
+ GstEvent * event);
+ int get_aac_parse_get_adts_frame_length (const unsigned char *data,
+ gint64 offset);
+ static gboolean gst_aac_parse_estimate_duration (GstBaseParse * parse);
+ #endif
+#define gst_aac_parse_parent_class parent_class
G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE);
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ static inline gint
+ gst_aac_parse_get_sample_rate_from_index (guint sr_idx)
+ {
+ static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
+ 32000, 24000, 22050, 16000, 12000, 11025, 8000
+ };
+
+ if (sr_idx < G_N_ELEMENTS (aac_sample_rates))
+ return aac_sample_rates[sr_idx];
+ GST_WARNING ("Invalid sample rate index %u", sr_idx);
+ return 0;
+ }
+ #endif
/**
* gst_aac_parse_class_init:
* @klass: #GstAacParseClass.
parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame);
parse_class->pre_push_frame =
GST_DEBUG_FUNCPTR (gst_aac_parse_pre_push_frame);
-#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_event);
++
++//#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION // FIXME
+ /* make full aac(adts) index table when seek */
- parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_eventfunc);
-#endif
++// parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_eventfunc);
++//#endif
}
GST_DEBUG ("initialized");
GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (aacparse));
GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (aacparse));
+
+ aacparse->last_parsed_sample_rate = 0;
+ aacparse->last_parsed_channels = 0;
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ /* to get more correct duration */
+ aacparse->first_frame = TRUE;
+ #endif
}
return res;
}
+static gboolean
+gst_aac_parse_src_event (GstBaseParse * parse, GstEvent * event)
+{
+ GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
+ aacparse->last_parsed_channels = 0;
+ aacparse->last_parsed_sample_rate = 0;
+ }
+
+ return GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+}
++
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ /**
+ * get_aac_parse_get_adts_framelength:
+ * @data: #GstBufferData.
+ * @offset: #GstBufferData offset
+ *
+ * Implementation to get adts framelength by using first some frame.
+ *
+ * Returns: frame size
+ */
+ int
+ get_aac_parse_get_adts_frame_length (const unsigned char *data, gint64 offset)
+ {
+ const gint adts_header_length_no_crc = 7;
+ const gint adts_header_length_with_crc = 9;
+ gint frame_size = 0;
+ gint protection_absent;
+ gint head_size;
+
+ /* check of syncword */
+ if ((data[offset + 0] != 0xff) || ((data[offset + 1] & 0xf6) != 0xf0)) {
+ GST_ERROR ("check sync word is fail\n");
+ return -1;
+ }
+
+ /* check of protection absent */
+ protection_absent = (data[offset + 1] & 0x01);
+
+ /*check of frame length */
+ frame_size =
+ (data[offset + 3] & 0x3) << 11 | data[offset + 4] << 3 | data[offset +
+ 5] >> 5;
+
+ /* check of header size */
+ /* protectionAbsent is 0 if there is CRC */
+ head_size =
+ protection_absent ? adts_header_length_no_crc :
+ adts_header_length_with_crc;
+ if (head_size > frame_size) {
+ GST_ERROR ("return frame length as 0 (frameSize %u < headSize %u)",
+ frame_size, head_size);
+ return 0;
+ }
+
+ return frame_size;
+ }
+
+ /**
+ * gst_aac_parse_estimate_duration:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation to get estimated total duration by using first some frame.
+ *
+ * Returns: TRUE if we can get estimated total duraion
+ */
+ static gboolean
+ gst_aac_parse_estimate_duration (GstBaseParse * parse)
+ {
+ gboolean ret = FALSE;
+ GstFlowReturn res = GST_FLOW_OK;
+ gint64 pull_size = 0, file_size = 0, offset = 0, num_frames = 0, duration = 0;
+ guint sample_rate_index = 0, sample_rate = 0, channel = 0;
+ guint frame_size = 0, frame_duration_us = 0, estimated_bitrate = 0;
+ guint lost_sync_count = 0;
+ GstClockTime estimated_duration = GST_CLOCK_TIME_NONE;
+ GstBuffer *buffer = NULL;
+ guint8 *buf = NULL;
+ gint i = 0;
+ GstPadMode pad_mode = GST_PAD_MODE_NONE;
+ GstAacParse *aacparse;
+ gint64 buffer_size = 0;
+ GstMapInfo map;
+
+ aacparse = GST_AAC_PARSE (parse);
+ GST_LOG_OBJECT (aacparse, "gst_aac_parse_estimate_duration enter");
+
+ /* check baseparse define these fuction */
+ gst_base_parse_get_pad_mode (parse, &pad_mode);
+ if (pad_mode != GST_PAD_MODE_PULL) {
+ GST_INFO_OBJECT (aacparse,
+ "aac parser is not pull mode. can not estimate duration");
+ return FALSE;
+ }
+
+ gst_base_parse_get_upstream_size (parse, &file_size);
+
+ if (file_size < ADIF_MAX_SIZE) {
+ GST_ERROR_OBJECT (aacparse, "file size is too short");
+ return FALSE;
+ }
+
+ pull_size = MIN (file_size, AAC_MAX_ESTIMATE_DURATION_BUF);
+
+ res = gst_pad_pull_range (parse->sinkpad, 0, pull_size, &buffer);
+ if (res != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (aacparse, "gst_pad_pull_range failed!");
+ return FALSE;
+ }
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ buf = map.data;
+ buffer_size = map.size;
+ if (buffer_size != pull_size) {
+ GST_ERROR_OBJECT (aacparse,
+ "We got different buffer_size(%" G_GINT64_FORMAT ") with pull_size(%"
+ G_GINT64_FORMAT ").", buffer_size, pull_size);
+ }
+
+ /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+ for (i = 0; i < buffer_size; i++) {
+ if ((buf[i] == 0xff) && ((buf[i + 1] & 0xf6) == 0xf0)) { /* aac sync word */
+ //guint profile = (buf[i+2] >> 6) & 0x3;
+ sample_rate_index = (buf[i + 2] >> 2) & 0xf;
+ sample_rate =
+ gst_aac_parse_get_sample_rate_from_index (sample_rate_index);
+ if (sample_rate == 0) {
+ GST_WARNING_OBJECT (aacparse, "Invalid sample rate index (0)");
+ goto EXIT;
+ }
+ channel = (buf[i + 2] & 0x1) << 2 | (buf[i + 3] >> 6);
+
+ GST_INFO_OBJECT (aacparse, "found sync. aac fs=%d, ch=%d", sample_rate,
+ channel);
+
+ /* count number of frames */
+ /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+ //while (offset < pull_size) {
+ while (offset < buffer_size) {
+ frame_size = get_aac_parse_get_adts_frame_length (buf, i + offset);
+ if (frame_size == 0) {
+ GST_ERROR_OBJECT (aacparse,
+ "framesize error at offset %" G_GINT64_FORMAT, offset);
+ break;
+ } else if (frame_size == -1) {
+ offset++;
+ lost_sync_count++; // lost sync count limmitation 2K Bytes
+ if (lost_sync_count > (1024 * 2)) {
+ GST_WARNING_OBJECT (aacparse,
+ "lost_sync_count is larger than 2048");
+ goto EXIT;
+ }
+ } else {
+ offset += frame_size;
+ num_frames++;
+ lost_sync_count = 0;
+ }
+ } /* while */
+
+ /* if we can got full file, we can calculate the accurate duration */
+ /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+ //if (pull_size == file_size) {
+ if (buffer_size == file_size) {
+ gfloat duration_for_one_frame = 0;
+ GstClockTime calculated_duration = GST_CLOCK_TIME_NONE;
+
+ GST_INFO_OBJECT (aacparse,
+ "we got total file (%" G_GINT64_FORMAT
+ " bytes). do not estimate but make Accurate total duration.",
+ pull_size);
+
+ duration_for_one_frame =
+ (gfloat) AAC_SAMPLE_PER_FRAME / (gfloat) sample_rate;
+ calculated_duration =
+ num_frames * duration_for_one_frame * 1000 * 1000 * 1000;
+
+ GST_INFO_OBJECT (aacparse, "duration_for_one_frame %f ms",
+ duration_for_one_frame);
+ GST_INFO_OBJECT (aacparse, "calculated duration = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (calculated_duration));
+ /* 0 means disable estimate */
+ gst_base_parse_set_duration (parse, GST_FORMAT_TIME,
+ calculated_duration, 0);
+
+ } else {
+ GST_INFO_OBJECT (aacparse,
+ "we got %" G_GUINT64_FORMAT " bytes in total file (%"
+ G_GINT64_FORMAT "). can not make accurate duration but Estimate.",
+ pull_size, file_size);
+ frame_duration_us =
+ (1024 * 1000000ll + (sample_rate - 1)) / sample_rate;
+ duration = num_frames * frame_duration_us;
+
+ if (duration == 0) {
+ GST_WARNING_OBJECT (aacparse, "Invalid duration");
+ goto EXIT;
+ }
+ estimated_bitrate =
+ (gint) ((gfloat) (offset * 8) / (gfloat) (duration / 1000));
+
+ if (estimated_bitrate == 0) {
+ GST_WARNING_OBJECT (aacparse, "Invalid estimated_bitrate");
+ goto EXIT;
+ }
+ estimated_duration =
+ (GstClockTime) ((file_size * 8) / (estimated_bitrate * 1000)) *
+ GST_SECOND;
+
+ GST_INFO_OBJECT (aacparse, "number of frame = %" G_GINT64_FORMAT,
+ num_frames);
+ GST_INFO_OBJECT (aacparse, "duration = %" G_GINT64_FORMAT,
+ duration / 1000000);
+ GST_INFO_OBJECT (aacparse, "byte = %" G_GINT64_FORMAT, offset);
+ GST_INFO_OBJECT (aacparse, "estimated bitrate = %d bps",
+ estimated_bitrate);
+ GST_INFO_OBJECT (aacparse, "estimated duration = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (estimated_duration));
+
+ gst_base_parse_set_average_bitrate (parse, estimated_bitrate * 1000);
+ /* set update_interval as duration(sec)/2 */
+ gst_base_parse_set_duration (parse, GST_FORMAT_TIME, estimated_duration,
+ (gint) (duration / 2));
+ }
+
+ break;
+ }
+ }
+ ret = TRUE;
+
+ EXIT:
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return ret;
+ }
+
+
+ /* perform seek in push based mode:
+ find BYTE position to move to based on time and delegate to upstream
+ */
+ static gboolean
+ gst_aac_audio_parse_do_push_seek (GstBaseParse * parse,
+ GstPad * pad, GstEvent * event)
+ {
+ GstAacParse *aacparse = GST_AAC_PARSE (parse);
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
+ gboolean res;
+ gint64 byte_cur;
+ gint64 esimate_byte;
+ gint32 frame_dur;
+ gint64 upstream_total_bytes = 0;
+ GstFormat fmt = GST_FORMAT_BYTES;
+
+ GST_INFO_OBJECT (parse, "doing aac push-based seek");
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+ &stop_type, &stop);
+
+ /* FIXME, always play to the end */
+ stop = -1;
+
+ /* only forward streaming and seeking is possible */
+ if (rate <= 0)
+ goto unsupported_seek;
+
+ if (cur == 0) {
+ /* handle rewind only */
+ cur_type = GST_SEEK_TYPE_SET;
+ byte_cur = 0;
+ stop_type = GST_SEEK_TYPE_NONE;
+ stop = -1;
+ flags |= GST_SEEK_FLAG_FLUSH;
+ } else {
+ /* handle normal seek */
+ cur_type = GST_SEEK_TYPE_SET;
+ stop_type = GST_SEEK_TYPE_NONE;
+ stop = -1;
+ flags |= GST_SEEK_FLAG_FLUSH;
+
+ esimate_byte = (cur / (1000 * 1000)) * aacparse->frame_byte;
+ if (aacparse->sample_rate > 0)
+ frame_dur = (aacparse->spf * 1000) / aacparse->sample_rate;
+ else
+ goto unsupported_seek;
+ if (frame_dur > 0)
+ byte_cur = esimate_byte / (frame_dur);
+ else
+ goto unsupported_seek;
+
+ GST_INFO_OBJECT (parse, "frame_byte(%d) spf(%d) rate (%d) ",
+ aacparse->frame_byte, aacparse->spf, aacparse->sample_rate);
+ GST_INFO_OBJECT (parse,
+ "seek cur (%" G_GINT64_FORMAT ") = (%" GST_TIME_FORMAT ") ", cur,
+ GST_TIME_ARGS (cur));
+ GST_INFO_OBJECT (parse,
+ "esimate_byte(%" G_GINT64_FORMAT ") esimate_byte (%d)", esimate_byte,
+ frame_dur);
+ }
+
+ /* obtain real upstream total bytes */
+ if (!gst_pad_peer_query_duration (parse->sinkpad, fmt, &upstream_total_bytes))
+ upstream_total_bytes = 0;
+ GST_INFO_OBJECT (aacparse,
+ "gst_pad_query_peer_duration -upstream_total_bytes (%" G_GUINT64_FORMAT
+ ")", upstream_total_bytes);
+ aacparse->file_size = upstream_total_bytes;
+
+ if ((byte_cur == -1) || (byte_cur > aacparse->file_size)) {
+ GST_INFO_OBJECT (parse,
+ "[WEB-ERROR] seek cur (%" G_GINT64_FORMAT ") > file_size (%"
+ G_GINT64_FORMAT ") ", cur, aacparse->file_size);
+ goto abort_seek;
+ }
+
+ GST_INFO_OBJECT (parse,
+ "Pushing BYTE seek rate %g, " "start %" G_GINT64_FORMAT ", stop %"
+ G_GINT64_FORMAT, rate, byte_cur, stop);
+
+ if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
+ GST_INFO_OBJECT (parse,
+ "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
+ G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
+ }
+
+ /* BYTE seek event */
+ event =
+ gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
+ stop_type, stop);
+ res = gst_pad_push_event (parse->sinkpad, event);
+
+ return res;
+
+ /* ERRORS */
+
+ abort_seek:
+ {
+ GST_DEBUG_OBJECT (parse,
+ "could not determine byte position to seek to, " "seek aborted.");
+ return FALSE;
+ }
+
+ unsupported_seek:
+ {
+ GST_DEBUG_OBJECT (parse, "unsupported seek, seek aborted.");
+ return FALSE;
+ }
+ }
+
+
+ static guint
+ gst_aac_parse_adts_get_fast_frame_len (const guint8 * data)
+ {
+ int length;
+ if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) {
+ length =
+ ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xe0) >> 5);
+ } else {
+ length = 0;
+ }
+ return length;
+ }
+
+ static gboolean
+ gst_aac_parse_src_eventfunc (GstBaseParse * parse, GstEvent * event)
+ {
+ gboolean handled = FALSE;
+ GstAacParse *aacparse;
+ aacparse = GST_AAC_PARSE (parse);
+
+ GST_DEBUG ("Entering gst_aac_parse_src_eventfunc header type = %d",
+ aacparse->header_type);
+ if (aacparse->header_type == DSPAAC_HEADER_ADTS)
+ return gst_aac_parse_adts_src_eventfunc (parse, event);
+ else
+ goto aac_seek_null_exit;
+ aac_seek_null_exit:
+
+ /* call baseparse src_event function to handle event */
+ handled = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+ return handled;
+ }
+
+ /**
+ * gst_aac_parse_adts_src_eventfunc:
+ * @parse: #GstBaseParse. #event
+ *
+ * before baseparse handles seek event, make full amr index table.
+ *
+ * Returns: TRUE on success.
+ */
+ static gboolean
+ gst_aac_parse_adts_src_eventfunc (GstBaseParse * parse, GstEvent * event)
+ {
+ gboolean handled = FALSE;
+ GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ {
+ GstFlowReturn res = GST_FLOW_OK;
+ gint64 base_offset = 0, cur = 0;
+ gint32 frame_count = 1; /* do not add first frame because it is already in index table */
+ gint64 second_count = 0; /* initial 1 second */
+ gint64 total_file_size = 0, start_offset = 0;
+ GstClockTime current_ts = GST_CLOCK_TIME_NONE;
+ GstPadMode pad_mode = GST_PAD_MODE_NONE;
+
+ /* check baseparse define these fuction */
+ gst_base_parse_get_pad_mode (parse, &pad_mode);
+ if (pad_mode != GST_PAD_MODE_PULL) {
+ gboolean ret = FALSE;
+ GstPad *srcpad = parse->srcpad;
+ GST_INFO_OBJECT (aacparse, "aac parser is PUSH MODE.");
+ /* check NULL */
+ ret = gst_aac_audio_parse_do_push_seek (parse, srcpad, event);
+ gst_object_unref (srcpad);
+ return ret;
+ }
+ gst_base_parse_get_upstream_size (parse, &total_file_size);
+ gst_base_parse_get_index_last_offset (parse, &start_offset);
+ gst_base_parse_get_index_last_ts (parse, ¤t_ts);
+
+ if (total_file_size > AAC_LARGE_FILE_SIZE) {
+ gst_base_parse_set_seek_mode (parse, 0);
+ GST_INFO_OBJECT (aacparse, "larger than big size (2MB).");
+ goto aac_seek_null_exit;
+ }
+
+ GST_DEBUG ("gst_aac_parse_adts_src_eventfunc GST_EVENT_SEEK enter");
+
+ if (total_file_size == 0 || start_offset >= total_file_size) {
+ GST_ERROR ("last index offset %" G_GINT64_FORMAT
+ " is larger than file size %" G_GINT64_FORMAT, start_offset,
+ total_file_size);
+ break;
+ }
+
+ gst_event_parse_seek (event, NULL, NULL, NULL, NULL, &cur, NULL, NULL);
+ if (cur <= current_ts) {
+ GST_INFO ("seek to %" GST_TIME_FORMAT " within index table %"
+ GST_TIME_FORMAT ". do not make index table", GST_TIME_ARGS (cur),
+ GST_TIME_ARGS (current_ts));
+ break;
+ } else {
+ GST_INFO ("seek to %" GST_TIME_FORMAT " without index table %"
+ GST_TIME_FORMAT ". make index table", GST_TIME_ARGS (cur),
+ GST_TIME_ARGS (current_ts));
+ }
+
+ GST_INFO ("make AAC(ADTS) Index Table. file_size = %" G_GINT64_FORMAT
+ " last idx offset=%" G_GINT64_FORMAT ", last idx ts=%"
+ GST_TIME_FORMAT, total_file_size, start_offset,
+ GST_TIME_ARGS (current_ts));
+
+ base_offset = start_offset; /* set base by start offset */
+ second_count = current_ts + GST_SECOND; /* 1sec */
+
+ /************************************/
+ /* STEP 0: Setting parse information */
+ /************************************/
+ aacparse->spf = aacparse->frame_samples;
+ aacparse->frame_duration = (aacparse->spf * 1000 * 100) / aacparse->sample_rate; /* duration per frame (msec) */
+ aacparse->frame_per_sec = (aacparse->sample_rate) / aacparse->spf; /* frames per second (ea) */
+
+ /************************************/
+ /* STEP 1: MAX_PULL_RANGE_BUF cycle */
+ /************************************/
+ while (total_file_size - base_offset >= AAC_MAX_PULL_RANGE_BUF) {
+ gint64 offset = 0;
+ GstBuffer *buffer = NULL;
+ guint8 *buf = NULL;
+ GstMapInfo map;
+ GST_INFO ("gst_pad_pull_range %d bytes (from %" G_GINT64_FORMAT
+ ") use max size", AAC_MAX_PULL_RANGE_BUF, base_offset);
+ res =
+ gst_pad_pull_range (parse->sinkpad, base_offset,
+ base_offset + AAC_MAX_PULL_RANGE_BUF, &buffer);
+ if (res != GST_FLOW_OK) {
+ GST_ERROR ("gst_pad_pull_range failed!");
+ break;
+ }
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ buf = map.data;
+ if (buf == NULL) {
+ gst_buffer_unmap (buffer, &map);
+ GST_WARNING ("buffer is NULL in make aac seek table's STEP1");
+ gst_buffer_unref (buffer);
+ goto aac_seek_null_exit;
+ }
+
+ while (offset <= AAC_MAX_PULL_RANGE_BUF) {
+ gint frame_size = 0;
+
+ /* make sure the values in the frame header look sane */
+ frame_size = gst_aac_parse_adts_get_fast_frame_len (buf);
+
+ if ((frame_size > 0)
+ && (frame_size < (AAC_MAX_PULL_RANGE_BUF - offset))) {
+ if (current_ts > second_count) { /* 1 sec == xx frames. we make idx per sec */
+ gst_base_parse_add_index_entry (parse, base_offset + offset, current_ts, TRUE, TRUE); /* force */
+ GST_DEBUG ("Adding index ts=%" GST_TIME_FORMAT " offset %"
+ G_GINT64_FORMAT, GST_TIME_ARGS (current_ts),
+ base_offset + offset);
+ second_count += GST_SECOND; /* 1sec */
+ }
+
+ current_ts += (aacparse->frame_duration * GST_MSECOND) / 100; /* each frame is (frame_duration) ms */
+ offset += frame_size;
+ buf += frame_size;
+ frame_count++;
+ } else if (frame_size >= (AAC_MAX_PULL_RANGE_BUF - offset)) {
+ GST_DEBUG ("we need refill buffer");
+ break;
+ } else {
+ GST_WARNING ("we lost sync");
+ buf++;
+ offset++;
+ }
+ } /* while */
+
+ base_offset = base_offset + offset;
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ } /* end MAX buffer cycle */
+
+ /*******************************/
+ /* STEP 2: Remain Buffer cycle */
+ /*******************************/
+ if (total_file_size - base_offset > 0) {
+ gint64 offset = 0;
+ GstBuffer *buffer = NULL;
+ guint8 *buf = NULL;
+ GstMapInfo map;
+
+ GST_INFO ("gst_pad_pull_range %" G_GINT64_FORMAT " bytes (from %"
+ G_GINT64_FORMAT ") use remain_buf size",
+ total_file_size - base_offset, base_offset);
+ res =
+ gst_pad_pull_range (parse->sinkpad, base_offset, total_file_size,
+ &buffer);
+ if (res != GST_FLOW_OK) {
+ GST_ERROR ("gst_pad_pull_range failed!");
+ break;
+ }
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ buf = map.data;
+ if (buf == NULL) {
+ gst_buffer_unmap (buffer, &map);
+ GST_WARNING ("buffer is NULL in make aac seek table's STEP2");
+ gst_buffer_unref (buffer);
+ goto aac_seek_null_exit;
+ }
+
+ while (base_offset + offset < total_file_size) {
+ gint frame_size = 0;
+
+ /* make sure the values in the frame header look sane */
+ frame_size = gst_aac_parse_adts_get_fast_frame_len (buf);
+
+ if ((frame_size > 0)
+ && (frame_size <= (total_file_size - (base_offset + offset)))) {
+ if (current_ts > second_count) { /* 1 sec == xx frames. we make idx per sec */
+ gst_base_parse_add_index_entry (parse, base_offset + offset, current_ts, TRUE, TRUE); /* force */
+ GST_DEBUG ("Adding index ts=%" GST_TIME_FORMAT " offset %"
+ G_GINT64_FORMAT, GST_TIME_ARGS (current_ts),
+ base_offset + offset);
+ second_count += GST_SECOND; /* 1sec */
+ }
+
+ current_ts += (aacparse->frame_duration * GST_MSECOND) / 100; /* each frame is (frame_duration) ms */
+ offset += frame_size;
+ buf += frame_size;
+ frame_count++;
+ } else if (frame_size == 0) {
+ GST_DEBUG ("Frame size is 0 so, Decoding end..");
+ break;
+ } else {
+ GST_WARNING ("we lost sync");
+ buf++;
+ offset++;
+ }
+ } /* while */
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ }
+ /* end remain_buf buffer cycle */
+ GST_DEBUG ("gst_aac_parse_adts_src_eventfunc GST_EVENT_SEEK leave");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ aac_seek_null_exit:
+
+ /* call baseparse src_event function to handle event */
+ handled = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+ return handled;
+ }
+ #endif //end of #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
PROP_DTS_METHOD,
#endif
PROP_DO_CTTS,
+ PROP_INTERLEAVE_BYTES,
+ PROP_INTERLEAVE_TIME,
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+ PROP_EXPECTED_TRAILER_SIZE,
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
};
/* some spare for header size as well */
"Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track",
0, 10000, DEFAULT_RESERVED_BYTES_PER_SEC_PER_TRAK,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INTERLEAVE_BYTES,
+ g_param_spec_uint64 ("interleave-bytes", "Interleave (bytes)",
+ "Interleave between streams in bytes",
+ 0, G_MAXUINT64, DEFAULT_INTERLEAVE_BYTES,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INTERLEAVE_TIME,
+ g_param_spec_uint64 ("interleave-time", "Interleave (time)",
+ "Interleave between streams in nanoseconds",
+ 0, G_MAXUINT64, DEFAULT_INTERLEAVE_TIME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+ tspec = g_param_spec_uint("expected-trailer-size", "Expected Trailer Size",
+ "Expected trailer size (bytes)",
+ 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ if (tspec)
+ g_object_class_install_property(gobject_class, PROP_EXPECTED_TRAILER_SIZE, tspec);
+ else
+ GST_ERROR("g_param_spec failed for \"expected-trailer-size\"");
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
+
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qt_mux_change_state);
}
}
- if (buf)
- gst_buffer_unref (buf);
-
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+ gst_qt_mux_update_expected_trailer_size(qtmux, pad);
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
+
exit:
return ret;
case PROP_RESERVED_BYTES_PER_SEC:
g_value_set_uint (value, qtmux->reserved_bytes_per_sec_per_trak);
break;
+ case PROP_INTERLEAVE_BYTES:
+ g_value_set_uint64 (value, qtmux->interleave_bytes);
+ break;
+ case PROP_INTERLEAVE_TIME:
+ g_value_set_uint64 (value, qtmux->interleave_time);
+ break;
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+ case PROP_EXPECTED_TRAILER_SIZE:
+ g_value_set_uint(value, qtmux->expected_trailer_size);
+ break;
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
+static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
+
+static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
+ QtDemuxStream * stream, guint sample_index);
static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
const gchar * id);
+static void qtdemux_gst_structure_free (GstStructure * gststructure);
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ static void gst_tag_register_spherical_tags (void);
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
+
static void
gst_qtdemux_class_init (GstQTDemuxClass * klass)
{
gst_tag_register_musicbrainz_tags ();
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_qtdemux_sink_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ gst_tag_register_spherical_tags ();
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
+
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_qtdemux_sink_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_qtdemux_videosrc_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_qtdemux_audiosrc_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_qtdemux_subsrc_template);
gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
"Codec/Demuxer",
"Demultiplex a QuickTime file into audio and video streams",
qtdemux->protection_system_ids = NULL;
g_queue_init (&qtdemux->protection_event_queue);
gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+ qtdemux->tag_list = gst_tag_list_new_empty ();
+ gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
qtdemux->flowcombiner = gst_flow_combiner_new ();
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ spherical_metadata = (QtDemuxSphericalMetadata *)
+ malloc (sizeof (QtDemuxSphericalMetadata));
+
+ if (spherical_metadata) {
+ spherical_metadata->is_spherical = FALSE;
+ spherical_metadata->is_stitched = FALSE;
+ spherical_metadata->stitching_software = NULL;
+ spherical_metadata->projection_type = NULL;
+ spherical_metadata->stereo_mode = NULL;
+ spherical_metadata->source_count = 0;
+ spherical_metadata->init_view_heading = 0;
+ spherical_metadata->init_view_pitch = 0;
+ spherical_metadata->init_view_roll = 0;
+ spherical_metadata->timestamp = 0;
+ spherical_metadata->full_pano_width_pixels = 0;
+ spherical_metadata->full_pano_height_pixels = 0;
+ spherical_metadata->cropped_area_image_width = 0;
+ spherical_metadata->cropped_area_image_height = 0;
+ spherical_metadata->cropped_area_left = 0;
+ spherical_metadata->cropped_area_top = 0;
+ spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
+ spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
+ spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
+ }
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
+
GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
}
GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
GST_DEBUG_PAD_NAME (stream->pad));
- if (G_UNLIKELY (stream->pending_tags)) {
+ if (!gst_tag_list_is_empty (stream->stream_tags)) {
GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
- stream->pending_tags);
+ stream->stream_tags);
gst_pad_push_event (stream->pad,
- gst_event_new_tag (stream->pending_tags));
+ gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ /* post message qtdemux tag (for early recive application) */
+ gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
+ gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
- gst_tag_list_copy (stream->pending_tags)));
++ gst_tag_list_copy (stream->stream_tags)));
+ #endif
- stream->pending_tags = NULL;
}
- if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
+ if (G_UNLIKELY (stream->send_global_tags)) {
GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
qtdemux->tag_list);
gst_pad_push_event (stream->pad,
}
}
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ static void
+ _get_int_value_from_xml_string (GstQTDemux * qtdemux,
+ const char *xml_str, const char *param_name, int *value)
+ {
+ char *value_start, *value_end, *endptr;
+ const short value_length_max = 12;
+ char init_view_ret[12];
+ int value_length = 0;
+ int i = 0;
+
+ value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+
+ if (!value_start) {
+ GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+ param_name);
+ return;
+ }
+
+ value_start += strlen (param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr (value_start, '<');
+ if (!value_end) {
+ GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+ return;
+ }
+
+ value_length = value_end - value_start;
+ while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+ || (value_start[value_length - 1] == '\t')))
+ value_length--;
+
+ if (value_start[i] == '+' || value_start[i] == '-')
+ i++;
+ while (i < value_length) {
+ if (value_start[i] < '0' || value_start[i] > '9') {
+ GST_ERROR_OBJECT (qtdemux,
+ "error: incorrect value, integer was expected\n");
+ return;
+ }
+ i++;
+ }
+
+ if (value_length >= value_length_max || value_length < 1) {
+ GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+ return;
+ }
+
+ strncpy (init_view_ret, value_start, value_length_max);
+ init_view_ret[value_length] = '\0';
+
+ *value = strtol (init_view_ret, &endptr, 10);
+ if (endptr == init_view_ret) {
+ GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
+ return;
+ }
+
+ return;
+ }
+
+ static void
+ _get_string_value_from_xml_string (GstQTDemux * qtdemux,
+ const char *xml_str, const char *param_name, char **value)
+ {
+ char *value_start, *value_end;
+ const short value_length_max = 256;
+ int value_length = 0;
+
+ value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+
+ if (!value_start) {
+ GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+ param_name);
+ return;
+ }
+
+ value_start += strlen (param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr (value_start, '<');
+ if (!value_end) {
+ GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+ return;
+ }
+
+ value_length = value_end - value_start;
+ while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+ || (value_start[value_length - 1] == '\t')))
+ value_length--;
+
+ if (value_length >= value_length_max || value_length < 1) {
+ GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+ return;
+ }
+
+ *value = (char *) malloc (value_length);
+
+ if (*value == NULL) {
+ GST_ERROR_OBJECT (qtdemux, "error: malloc failed\n");
+ return;
+ }
+
+ strncpy (*value, value_start, value_length);
+
+ return;
+ }
+
+ static void
+ _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
+ const char *xml_str, const char *param_name, gboolean * value)
+ {
+ char *value_start, *value_end;
+ int value_length = 0;
+
+ value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+
+ if (!value_start) {
+ GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+ param_name);
+ return;
+ }
+
+ value_start += strlen (param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr (value_start, '<');
+ if (!value_end) {
+ GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+ return;
+ }
+
+ value_length = value_end - value_start;
+ while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+ || (value_start[value_length - 1] == '\t')))
+ value_length--;
+
+ if (value_length < 1) {
+ GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+ return;
+ }
+
+ *value = strstr (value_start, "true") ? TRUE : FALSE;
+
+ return;
+ }
+
+ static void
+ _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux,
+ const char *xmlStr, QtDemuxSphericalMetadata * spherical_metadata)
+ {
+ const char is_spherical_str[] = "<GSpherical:Spherical>";
+ const char is_stitched_str[] = "<GSpherical:Stitched>";
+ const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
+ const char projection_type_str[] = "<GSpherical:ProjectionType>";
+ const char stereo_mode_str[] = "<GSpherical:StereoMode>";
+ const char source_count_str[] = "<GSpherical:SourceCount>";
+ const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
+ const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
+ const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
+ const char timestamp_str[] = "<GSpherical:Timestamp>";
+ const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
+ const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
+ const char cropped_area_image_width_str[] =
+ "<GSpherical:CroppedAreaImageWidthPixels>";
+ const char cropped_area_image_height_str[] =
+ "<GSpherical:CroppedAreaImageHeightPixels>";
+ const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
+ const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
+
+ _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
+ (gboolean *) & spherical_metadata->is_spherical);
+ _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
+ (gboolean *) & spherical_metadata->is_stitched);
+
+ if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
+ _get_string_value_from_xml_string (qtdemux, xmlStr,
+ stitching_software_str, &spherical_metadata->stitching_software);
+ _get_string_value_from_xml_string (qtdemux, xmlStr,
+ projection_type_str, &spherical_metadata->projection_type);
+ _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
+ &spherical_metadata->stereo_mode);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
+ &spherical_metadata->source_count);
+ _get_int_value_from_xml_string (qtdemux, xmlStr,
+ init_view_heading_str, &spherical_metadata->init_view_heading);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
+ &spherical_metadata->init_view_pitch);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
+ &spherical_metadata->init_view_roll);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
+ &spherical_metadata->timestamp);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
+ &spherical_metadata->full_pano_width_pixels);
+ _get_int_value_from_xml_string (qtdemux, xmlStr,
+ full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
+ _get_int_value_from_xml_string (qtdemux, xmlStr,
+ cropped_area_image_width_str,
+ &spherical_metadata->cropped_area_image_width);
+ _get_int_value_from_xml_string (qtdemux, xmlStr,
+ cropped_area_image_height_str,
+ &spherical_metadata->cropped_area_image_height);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
+ &spherical_metadata->cropped_area_left);
+ _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
+ &spherical_metadata->cropped_area_top);
+ }
+
+ return;
+ }
+
+ static void
+ gst_tag_register_spherical_tags (void) {
+ gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-spherical"),
+ _("Flag indicating if the video is a spherical video"),
+ NULL);
+ gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-stitched"),
+ _("Flag indicating if the video is stitched"),
+ NULL);
+ gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
+ G_TYPE_STRING,
+ _("tag-stitching-software"),
+ _("Software used to stitch the spherical video"),
+ NULL);
+ gst_tag_register ("projection_type", GST_TAG_FLAG_META,
+ G_TYPE_STRING,
+ _("tag-projection-type"),
+ _("Projection type used in the video frames"),
+ NULL);
+ gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
+ G_TYPE_STRING,
+ _("tag-stereo-mode"),
+ _("Description of stereoscopic 3D layout"),
+ NULL);
+ gst_tag_register ("source_count", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-source-count"),
+ _("Number of cameras used to create the spherical video"),
+ NULL);
+ gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-init-view-heading"),
+ _("The heading angle of the initial view in degrees"),
+ NULL);
+ gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-init-view-pitch"),
+ _("The pitch angle of the initial view in degrees"),
+ NULL);
+ gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-init-view-roll"),
+ _("The roll angle of the initial view in degrees"),
+ NULL);
+ gst_tag_register ("timestamp", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-timestamp"),
+ _("Epoch timestamp of when the first frame in the video was recorded"),
+ NULL);
+ gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-full-pano-width"),
+ _("Width of the encoded video frame in pixels"),
+ NULL);
+ gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-full-pano-height"),
+ _("Height of the encoded video frame in pixels"),
+ NULL);
+ gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-cropped-area-image-width"),
+ _("Width of the video frame to display (e.g. cropping)"),
+ NULL);
+ gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-cropped-area-image-height"),
+ _("Height of the video frame to display (e.g. cropping)"),
+ NULL);
+ gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-cropped-area-left"),
+ _("Column where the left edge of the image was cropped from the"
+ " full sized panorama"),
+ NULL);
+ gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-cropped-area-top"),
+ _("Row where the top edge of the image was cropped from the"
+ " full sized panorama"),
+ NULL);
+ gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-ambisonic-type"),
+ _("Specifies the type of ambisonic audio represented"),
+ NULL);
+ gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-ambisonic-format"),
+ _("Specifies the ambisonic audio format"),
+ NULL);
+ gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
+ G_TYPE_INT,
+ _("tag-ambisonic-order"),
+ _("Specifies the ambisonic audio channel order"),
+ NULL);
+
+ return;
+ }
+
+ static void
+ _send_message_to_bus (GstQTDemux * qtdemux,
+ QtDemuxSphericalMetadata * spherical_metadata)
+ {
+ GstTagList *taglist;
+
+ GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
+ spherical_metadata->is_spherical);
+ GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
+ spherical_metadata->is_stitched);
+ GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
+ spherical_metadata->stitching_software);
+ GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
+ spherical_metadata->projection_type);
+ GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
+ spherical_metadata->stereo_mode);
+ GST_DEBUG_OBJECT (qtdemux, "source_count %d",
+ spherical_metadata->source_count);
+ GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
+ spherical_metadata->init_view_heading);
+ GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
+ spherical_metadata->init_view_pitch);
+ GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
+ spherical_metadata->init_view_roll);
+ GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
+ GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
+ spherical_metadata->full_pano_width_pixels);
+ GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
+ spherical_metadata->full_pano_height_pixels);
+ GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
+ spherical_metadata->cropped_area_image_width);
+ GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
+ spherical_metadata->cropped_area_image_height);
+ GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
+ spherical_metadata->cropped_area_left);
+ GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
+ spherical_metadata->cropped_area_top);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
+ spherical_metadata->ambisonic_type);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
+ spherical_metadata->ambisonic_order);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
+ spherical_metadata->ambisonic_format);
+
+ taglist = gst_tag_list_new_empty ();
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+ "is_spherical", spherical_metadata->is_spherical,
+ "is_stitched", spherical_metadata->is_stitched,
+ "source_count", spherical_metadata->source_count,
+ "init_view_heading", spherical_metadata->init_view_heading,
+ "init_view_pitch", spherical_metadata->init_view_pitch,
+ "init_view_roll", spherical_metadata->init_view_roll,
+ "timestamp", spherical_metadata->timestamp,
+ "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
+ "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
+ "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
+ "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
+ "cropped_area_left", spherical_metadata->cropped_area_left,
+ "cropped_area_top", spherical_metadata->cropped_area_top,
+ "ambisonic_type", spherical_metadata->ambisonic_type,
+ "ambisonic_format", spherical_metadata->ambisonic_format,
+ "ambisonic_order", spherical_metadata->ambisonic_order,
+ NULL);
+
+ if (spherical_metadata->stitching_software)
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+ "stitching_software", spherical_metadata->stitching_software,
+ NULL);
+ if (spherical_metadata->projection_type)
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+ "projection_type", spherical_metadata->projection_type,
+ NULL);
+ if (spherical_metadata->stereo_mode)
+ gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+ "stereo_mode", spherical_metadata->stereo_mode,
+ NULL);
+
+ gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
+ gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
+ gst_tag_list_copy (taglist)));
+
+ gst_tag_list_unref(taglist);
+
+ return;
+ }
+
+ static void
+ qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+ {
+ guint offset = 0;
+
+ guint8 version = 0;
+ guint8 ambisonic_type = 0;
+ guint32 ambisonic_order = 0;
+ guint8 ambisonic_channel_ordering = 0;
+ guint8 ambisonic_normalization = 0;
+ guint32 num_channels = 0;
+ guint32 channel_map[49] = { 0 }; /* Up to 6th order */
+
+ int i;
+
+ GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
+
+ qtdemux->header_size += length;
+ offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
+
+ if (length <= offset + 16) {
+ GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
+ return;
+ }
+
+ version = QT_UINT8 (buffer + offset);
+ ambisonic_type = QT_UINT8 (buffer + offset + 1);
+ ambisonic_order = QT_UINT32 (buffer + offset + 2);
+ ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
+ ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
+ num_channels = QT_UINT32 (buffer + offset + 8);
+ for (i = 0; i < num_channels; ++i)
+ channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
+
+ GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
+ ambisonic_channel_ordering);
+ GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
+ ambisonic_normalization);
+ GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
+ for (i = 0; i < num_channels; ++i)
+ GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
+
+ if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
+ if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
+ spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
+
+ if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
+ if (num_channels == 4) {
+ spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
+
+ if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
+ && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
+ && (channel_map[0] == 0) && (channel_map[1] == 1)
+ && (channel_map[2] == 2) && (channel_map[3] == 3))
+ spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
+
+ if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
+ && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
+ && (channel_map[0] == 0) && (channel_map[1] == 3)
+ && (channel_map[2] == 1) && (channel_map[3] == 2))
+ spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
+ }
+ }
+ }
+
+ return;
+ }
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
+
static void
-qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
+ guint offset)
{
- static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
- 0x97, 0xA9, 0x42, 0xE8,
- 0x9C, 0x71, 0x99, 0x94,
- 0x91, 0xE3, 0xAF, 0xAC
- };
- static const guint8 playready_uuid[] = {
- 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
- 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
- };
-
-#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
- static const guint8 spherical_uuid[] = {
- 0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
- 0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
- };
-#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
-
- guint offset;
+ GstByteReader br;
+ guint8 version;
+ guint32 flags = 0;
+ guint i;
+ guint8 iv_size = 8;
+ QtDemuxStream *stream;
+ GstStructure *structure;
+ QtDemuxCencSampleSetInfo *ss_info = NULL;
+ const gchar *system_id;
+ gboolean uses_sub_sample_encryption = FALSE;
- /* counts as header data */
- qtdemux->header_size += length;
+ if (qtdemux->n_streams == 0)
+ return;
- offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
+ stream = qtdemux->streams[0];
- if (length <= offset + 16) {
- GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
+ structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
+ if (!gst_structure_has_name (structure, "application/x-cenc")) {
+ GST_WARNING_OBJECT (qtdemux,
+ "Attempting PIFF box parsing on an unencrypted stream.");
return;
}
{FOURCC_schi, "scheme information", QT_FLAG_CONTAINER},
{FOURCC_pssh, "protection system specific header", 0},
{FOURCC_tenc, "track encryption", 0},
+ {FOURCC_stpp, "XML subtitle sample entry", 0},
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ {FOURCC_SA3D, "spatial sound", 0,},
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
{0, "unknown", 0,},
};
g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
g_object_set (buffer, "mode", rtpbin->buffer_mode, NULL);
g_object_set (buffer, "do-retransmission", rtpbin->do_retransmission, NULL);
+ g_object_set (buffer, "max-rtcp-rtp-time-diff",
+ rtpbin->max_rtcp_rtp_time_diff, NULL);
+ g_object_set (buffer, "max-dropout-time", rtpbin->max_dropout_time,
+ "max-misorder-time", rtpbin->max_misorder_time, NULL);
+ g_object_set (buffer, "rfc7273-sync", rtpbin->rfc7273_sync, NULL);
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ /* configure queue2 to use live buffering */
+ if (queue2) {
+ g_object_set_data (G_OBJECT (queue2), "GstRTPBin.stream", stream);
+ g_object_set (queue2, "use-buffering", TRUE, NULL);
+ g_object_set (queue2, "buffer-mode", GST_BUFFERING_LIVE, NULL);
+ }
+ #endif
+
g_signal_emit (rtpbin, gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER], 0,
buffer, session->id, ssrc);
#define DEFAULT_DO_RETRANSMISSION TRUE
#define DEFAULT_NTP_TIME_SOURCE NTP_TIME_SOURCE_NTP
#define DEFAULT_USER_AGENT "GStreamer/" PACKAGE_VERSION
+#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
+#define DEFAULT_RFC7273_SYNC FALSE
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ #define DEFAULT_START_POSITION 0
+ #endif
+
enum
{
PROP_0,
src->do_retransmission = DEFAULT_DO_RETRANSMISSION;
src->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+ src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
+ src->rfc7273_sync = DEFAULT_RFC7273_SYNC;
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ g_mutex_init (&(src)->pause_lock);
+ g_cond_init (&(src)->open_end);
+ #endif
/* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get ();
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
("Could not receive any UDP packets for %.4f seconds, maybe your "
"firewall is blocking it. No other protocols to try.",
- gst_guint64_to_gdouble (src->udp_timeout / 1000000.0)));
+ gst_guint64_to_gdouble (src->udp_timeout) / 1000000.0));
+ #endif
return GST_RTSP_ERROR;
}
open_failed:
switch (response->type_data.response.code) {
case GST_RTSP_STS_NOT_FOUND:
- GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s",
- response->type_data.response.reason));
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ gst_rtspsrc_post_error_message (src, GST_RTSPSRC_ERROR_BAD_REQUEST,
+ "STS NOT FOUND");
+ #else
+ RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, NOT_FOUND,
+ "Not found");
+ #endif
break;
case GST_RTSP_STS_UNAUTHORIZED:
- GST_ELEMENT_ERROR (src, RESOURCE, NOT_AUTHORIZED, (NULL), ("%s",
- response->type_data.response.reason));
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ gst_rtspsrc_post_error_message (src, GST_RTSPSRC_ERROR_NOT_AUTHORIZED,
+ "STS NOT AUTHORIZED");
+ #else
+ RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, NOT_AUTHORIZED,
+ "Unauthorized");
+ #endif
break;
case GST_RTSP_STS_MOVED_PERMANENTLY:
case GST_RTSP_STS_MOVE_TEMPORARILY:
res = GST_RTSP_OK;
break;
default:
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Got error response: %d (%s).", response->type_data.response.code,
- response->type_data.response.reason));
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ gst_rtspsrc_post_error_message (src, GST_RTSPSRC_ERROR_UNEXPECTED_MSG,
+ "Got error response from Server");
+ #else
+ RTSP_SRC_RESPONSE_ERROR (src, response, RESOURCE, READ,
+ "Unhandled error");
+ #endif
break;
}
/* if we return ERROR we should unset the response ourselves */
--- /dev/null
-Version: 1.6.1
-Release: 17
+ %bcond_with x
+ %define gst_branch 1.0
+
+ Name: gst-plugins-good
-%{_libdir}/gstreamer-%{gst_branch}/libgstpulse.so
++Version: 1.12.2
++Release: 0
+ License: LGPL-2.1+
+ Summary: GStreamer Streaming-Media Framework Plug-Ins
+ Url: http://gstreamer.freedesktop.org/
+ Group: Multimedia/Framework
+ Source: http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-%{version}.tar.xz
+ Source100: common.tar.gz
+ BuildRequires: gcc-c++
+ BuildRequires: gettext-tools
+ BuildRequires: pkgconfig(glib-2.0) >= 2.32
+ BuildRequires: pkgconfig(gstreamer-1.0)
+ BuildRequires: pkgconfig(gstreamer-plugins-base-1.0)
+ BuildRequires: libjpeg-devel
+ BuildRequires: orc >= 0.4.16
+ BuildRequires: python
+ BuildRequires: xsltproc
+ BuildRequires: pkgconfig(bzip2)
+ #BuildRequires: pkgconfig(libpng) >= 1.2
+ BuildRequires: pkgconfig(libpulse) >= 1.0
+ BuildRequires: pkgconfig(libsoup-2.4)
+ BuildRequires: pkgconfig(libxml-2.0) >= 2.4.9
+ # TODO find where process.h comes from, not kernel-devel and not wxWidgets so far.
+ %if %{with x}
+ BuildRequires: pkgconfig(ice)
+ BuildRequires: pkgconfig(sm)
+ BuildRequires: pkgconfig(xdamage)
+ BuildRequires: pkgconfig(xfixes)
+ # used by libgstvideo4linux2.so
+ BuildRequires: pkgconfig(xv)
+ %endif
+
+ BuildRequires: pkgconfig(zlib)
+ %if "%{TIZEN_PRODUCT_TV}" != "1"
+ BuildRequires: pkgconfig(libv4l2)
+ %endif
+ BuildRequires: pkgconfig(vconf)
+ Requires: gst-plugins-base >= 1.0.0
+ Requires: gstreamer >= 1.0.5
+
+ %description
+ GStreamer is a streaming media framework based on graphs of filters
+ that operate on media data. Applications using this library can do
+ anything media-related, from real-time sound processing to playing
+ videos. Its plug-in-based architecture means that new data types or
+ processing capabilities can be added simply by installing new plug-ins.
+
+ %package extra
+ Summary: Complementary plugins for %{name}
+ Group: Productivity/Multimedia/Other
+ Requires: %{name} = %{version}
+ Enhances: gst-plugins-good
+
+ %description extra
+ This package provides complementary plugins for
+ %{name}.
+
+ %prep
+ %setup -q -n gst-plugins-good-%{version}
+ %setup -q -T -D -a 100
+
+ %build
+ # FIXME:
+ # warning: failed to load external entity "xml/element-v4l2src-details.xml"
+ # warning: failed to load external entity "xml/plugin-video4linux2.xml"
+ export V=1
+ NOCONFIGURE=1 ./autogen.sh
+ export CFLAGS+=" -DTIZEN_FEATURE_V4L2SRC_MODIFICATION\
+ -DTIZEN_FEATURE_WAVPARSE_MODIFICATION\
+ -DTIZEN_FEATURE_MP3PARSE_MODIFICATION\
+ -DTIZEN_FEATURE_AACPARSE_MODIFICATION\
+ -DTIZEN_FEATURE_QTDEMUX_MODIFICATION\
+ -DTIZEN_FEATURE_FLVDEMUX_MODIFICATION\
+ -DTIZEN_FEATURE_GST_UPSTREAM\
+ -DTIZEN_FEATURE_RTSP_MODIFICATION\
+ -DTIZEN_FEATURE_GST_MUX_ENHANCEMENT\
+ -DTIZEN_FEATURE_SOUP_MODIFICATION\
+ -DTIZEN_FEATURE_BASEPARSE_MODIFICATION"
+ %configure\
+ %if ! 0%{?ENABLE_AALIB}
+ --disable-aalib\
+ %endif
+ %if "%{TIZEN_PRODUCT_TV}" != "1"
+ --with-libv4l2 \
+ %endif
+ --disable-gtk-doc\
+ --with-gtk=3.0\
+ --disable-monoscope\
+ --disable-y4m\
+ --disable-taglib\
+ --disable-wavpack\
+ --enable-experimental\
+ %if "%{TIZEN_PRODUCT_TV}" == "1"
+ --disable-equalizer\
+ --disable-flv\
+ --disable-videobox\
+ --disable-videomixer\
+ %endif
+ --disable-effectv\
+ --disable-alpha\
+ --disable-auparse\
+ --disable-effectv\
+ --disable-flx\
+ --disable-goom\
+ --disable-goom2k1\
+ --disable-level\
+ --disable-multipart\
+ --disable-replaygain\
+ --disable-smpte\
+ --disable-spectrum\
+ --disable-cutter\
+ --disable-dtmf\
+ --disable-imagefreeze\
+ --disable-oss4\
+ --disable-oss\
+ --disable-shapewipe
+
+ make %{?_smp_mflags} CFLAGS+="-Wno-error" CXXFLAGS+="-Wno-error"
+
+ %install
+ %make_install
+ %find_lang %{name}-%{gst_branch}
+
+ %lang_package -f %{name}-%{gst_branch}
+
+ %files
+ %manifest %{name}.manifest
+ %defattr(-, root, root)
+ %license COPYING
+ %{_libdir}/gstreamer-%{gst_branch}/libgstalaw.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstalpha.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstalphacolor.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstapetag.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaudiofx.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaudioparsers.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstauparse.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstautodetect.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstavi.so
+ # Not yet ported
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstcutter.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstdebug.so
+ # Not yet ported
+ %{_libdir}/gstreamer-%{gst_branch}/libgstdeinterlace.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgsteffectv.so
+
+ #%{_datadir}/gstreamer-%{gst_branch}/presets/GstVP8Enc.prs
+
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstflxdec.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstgoom.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstgoom2k1.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgsticydemux.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstid3demux.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstimagefreeze.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstinterleave.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstisomp4.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstjpeg.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstlevel.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmatroska.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstmonoscope.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmulaw.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmultifile.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstmultipart.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstnavigationtest.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstoss4audio.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstossaudio.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstpng.so
-%{_libdir}/gstreamer-%{gst_branch}/libgstsouphttpsrc.so
++%{_libdir}/gstreamer-%{gst_branch}/libgstpulseaudio.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstreplaygain.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtp.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtpmanager.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtsp.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstshapewipe.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstsmpte.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstspectrum.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstspeex.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstudp.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideo4linux2.so
+
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideocrop.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideofilter.so
+ %if "%{TIZEN_PRODUCT_TV}" != "1"
+ %{_libdir}/gstreamer-%{gst_branch}/libgstflv.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstequalizer.so
+ %{_datadir}/gstreamer-%{gst_branch}/presets/GstIirEqualizer10Bands.prs
+ %{_datadir}/gstreamer-%{gst_branch}/presets/GstIirEqualizer3Bands.prs
++%{_datadir}/gstreamer-%{gst_branch}/presets/GstQTMux.prs
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideobox.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideomixer.so
+ %endif
+ %{_libdir}/gstreamer-%{gst_branch}/libgstwavenc.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstwavparse.so
+ %if %{with x}
+ %{_libdir}/gstreamer-%{gst_branch}/libgstximagesrc.so
+ %endif
+ #%{_libdir}/gstreamer-%{gst_branch}/libgsty4menc.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstcairo.so
++%{_libdir}/gstreamer-%{gst_branch}/libgstsoup.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstflac.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstvpx.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstdtmf.so
+
+
+ %if 0%{?ENABLE_AALIB}
+ %files extra
+ %manifest %{name}.manifest
+ %defattr(-, root, root)
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaasink.so
+ %endif
v4l2object->video_fd = libv4l2_fd;
/* get capabilities, error will be posted */
+ #ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+ if (!gst_v4l2_get_capabilities (v4l2object)) {
+ error_type = V4L2_OPEN_ERROR;
+ goto pre_error_check;
+ }
+ #else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
if (!gst_v4l2_get_capabilities (v4l2object))
goto error;
+ #endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
/* do we need to be a capture device? */
- GST_INFO_OBJECT(v4l2object->element, "capabilities 0x%x", v4l2object->vcap.capabilities);
+ #ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
- (!(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
- (v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) {
++ GST_INFO_OBJECT(v4l2object->element, "device_caps 0x%x", v4l2object->device_caps);
+ if (GST_IS_V4L2SRC (v4l2object->element) &&
++ (!(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
++ (v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) {
+ error_type = V4L2_OPEN_ERROR_NOT_CAPTURE;
+ goto pre_error_check;
+ }
+ #else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
if (GST_IS_V4L2SRC (v4l2object->element) &&
- !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_CAPTURE |
+ !(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
goto not_capture;
+ #endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
- !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+ #ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+ if (GST_IS_V4L2SINK (v4l2object->element) &&
++ !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE))) {
+ error_type = V4L2_OPEN_ERROR_NOT_OUTPUT;
+ goto pre_error_check;
+ }
+ #else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
if (GST_IS_V4L2SINK (v4l2object->element) &&
- !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+ !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
goto not_output;
+ #endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
/* Today's M2M device only expose M2M */