From b80b2a513fb1501119f5d4a1da3c27ad43020dda Mon Sep 17 00:00:00 2001 From: "jk7744.park" Date: Tue, 8 Sep 2015 22:28:22 +0900 Subject: [PATCH] tizen 2.3.1 release --- autogen.sh | 13 - configure.ac | 19 + debian/changelog | 377 ++++++++++++++++ debian/compat | 1 + debian/control | 110 +++++ debian/copyright | 31 ++ debian/gstreamer-tools.install | 2 + debian/gstreamer0.10-tools.install | 2 + debian/libgstreamer0.10-0.install | 2 + debian/libgstreamer0.10-dev.install | 1 + debian/libgstreamer0.10-sdk-dev.install | 4 + debian/rules | 113 +++++ gst/Makefile.am | 7 +- gst/gst.c | 9 - gst/gstbin.c | 13 + gst/gstbuffer.c | 31 ++ gst/gstcaps.c | 5 + gst/gstelement.c | 8 - gst/gstelementfactory.c | 7 - gst/gstinfo.c | 31 ++ gst/gstplugin.c | 6 - gst/gststructure.c | 4 + gst/gstsystemclock.c | 53 ++- gst/gstsystemclock.h | 13 +- gstreamer-tools.manifest | 8 + gstreamer.manifest | 9 + libs/gst/base/gstbaseparse.c | 576 +++++++++++++++++++++++-- libs/gst/base/gstbaseparse.h | 29 ++ libs/gst/base/gstbasesink.c | 732 ++++++++++++++++++++++++++++---- libs/gst/base/gstbasesrc.c | 15 - libs/gst/base/gstbasesrc.h | 3 - libs/gst/base/gstcollectpads.c | 59 +++ libs/gst/base/gstcollectpads.h | 11 + libs/gst/base/gstdataqueue.c | 75 ++++ libs/gst/base/gstdataqueue.h | 3 + libs/gst/helpers/Makefile.am | 2 +- packaging/gstreamer-registry.service | 14 + packaging/gstreamer.spec | 35 +- pkgconfig/gstreamer-base.pc.in | 2 +- plugins/elements/gstfilesink.c | 19 + plugins/elements/gstfilesrc.c | 21 + plugins/elements/gstmultiqueue.c | 101 ++++- plugins/elements/gstqueue.c | 15 +- plugins/elements/gstqueue2.c | 357 +++++++++++++++- plugins/elements/gstqueue2.h | 2 + tools/Makefile.am | 10 +- tools/gst-feedback-m.m | 54 +-- win32/common/libgstbase.def | 1 + 48 files changed, 2758 insertions(+), 257 deletions(-) mode change 100644 => 100755 configure.ac create mode 100755 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/gstreamer-tools.install create mode 100644 debian/gstreamer0.10-tools.install create mode 100644 debian/libgstreamer0.10-0.install create mode 100644 debian/libgstreamer0.10-dev.install create mode 100644 debian/libgstreamer0.10-sdk-dev.install create mode 100755 debian/rules mode change 100644 => 100755 gst/Makefile.am mode change 100644 => 100755 gst/gstcaps.c create mode 100755 gstreamer-tools.manifest create mode 100755 gstreamer.manifest create mode 100644 packaging/gstreamer-registry.service mode change 100644 => 100755 plugins/elements/gstmultiqueue.c diff --git a/autogen.sh b/autogen.sh index c0cd19e..14d980b 100755 --- a/autogen.sh +++ b/autogen.sh @@ -41,8 +41,6 @@ version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 60 || DIE=1 version_check "automake" "$AUTOMAKE automake automake-1.11 automake-1.10" \ "ftp://ftp.gnu.org/pub/gnu/automake/" 1 10 || DIE=1 -version_check "autopoint" "autopoint" \ - "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 version_check "libtoolize" "libtoolize libtoolize15 glibtoolize" \ "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1 version_check "pkg-config" "" \ @@ -66,17 +64,6 @@ fi toplevel_check $srcfile -# autopoint -# older autopoint (< 0.12) has a tendency to complain about mkinstalldirs -if test -x mkinstalldirs; then rm mkinstalldirs; fi -# first remove patch if necessary, then run autopoint, then reapply -if test -f po/Makefile.in.in; -then - patch -p0 -R --forward < common/gettext.patch -fi -tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch" -patch -p0 < common/gettext.patch - # aclocal if test -f acinclude.m4; then rm acinclude.m4; fi diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index ce14bf0..913c902 --- a/configure.ac +++ b/configure.ac @@ -584,6 +584,25 @@ AC_ARG_ENABLE(check, *) BUILD_CHECK=yes ;; esac ]) + +dnl use dlog -------------------------------------------------------------------------- +AC_ARG_ENABLE(dlog, AC_HELP_STRING([--enable-dlog], [using dlog]), +[ + case "${enableval}" in + yes) USE_DLOG=yes ;; + no) USE_DLOG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-dlog) ;; + esac +],[USE_DLOG=no]) + +if test "x$USE_DLOG" = "xyes"; then + PKG_CHECK_MODULES(DLOG, dlog) + AC_SUBST(DLOG_CFLAGS) + AC_SUBST(DLOG_LIBS) +fi +AM_CONDITIONAL(USE_DLOG, test "x$USE_DLOG" = "xyes") +dnl end -------------------------------------------------------------------- + dnl bit of a misnomer, but keep the conditional named like this so we don't dnl have to change too much elsewhere AM_CONDITIONAL(HAVE_CHECK, test "x$BUILD_CHECK" = "xyes") diff --git a/debian/changelog b/debian/changelog new file mode 100755 index 0000000..f0ffaa5 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,377 @@ +gstreamer0.10 (0.10.36-1slp2+11) unstable; urgency=low + + * [queue2]add posix_fadvise because of page cache free after streaming + * Tag: gstreamer0.10_0.10.36-1slp2+11 + + -- Jihae Yi Mon, 29 Apr 2013 17:53:45 +0900 + +gstreamer0.10 (0.10.36-1slp2+10) unstable; urgency=low + + * [filesink] Call posix_fadvise not to use page cache + * Tag: gstreamer0.10_0.10.36-1slp2+10 + + -- Jeongmo Yang Mon, 22 Apr 2013 17:53:23 +0900 + +gstreamer0.10 (0.10.36-1slp2+9) unstable; urgency=low + + * [queue] flush queue when empty-buffers is set as TRUE + * Tag: gstreamer0.10_0.10.36-1slp2+9 + + -- Jeongmo Yang Thu, 24 Jan 2013 20:31:39 +0900 + +gstreamer0.10 (0.10.36-1slp2+7) unstable; urgency=low + + * [baseparse] Modify to do not calculate zero padding in first frame + * Git: framework/multimedia/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+7 + + -- Sunghyun Eum Fri, 16 Nov 2012 11:38:36 +0900 + +gstreamer0.10 (0.10.36-1slp2+6) unstable; urgency=low + + * [gststructure] Add null check code for avoid seg. fault + * Git: framework/multimedia/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+6 + + -- Sunghyun Eum Tue, 23 Oct 2012 14:23:12 +0900 + +gstreamer0.10 (0.10.36-1slp2+5) unstable; urgency=low + + * [baseparse] Add get baseparser pad_mode param function for aac duration + * Git: framework/multimedia/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+5 + + -- Sunghyun Eum Thu, 04 Oct 2012 23:31:38 +0900 + +gstreamer0.10 (0.10.36-1slp2+4) unstable; urgency=low + + * [baseparse] Add get baseparser private param function for amr index table + * Git: framework/multimedia/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+4 + + -- Sunghyun Eum Fri, 28 Sep 2012 18:02:03 +0900 + +gstreamer0.10 (0.10.36-1slp2+3) unstable; urgency=low + + * add default smack manifest + * Git: framework/multimedia/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+3 + + -- Sangchul Lee Fri, 21 Sep 2012 13:12:24 +0900 + +gstreamer0.10 (0.10.36-1slp2+2) unstable; urgency=low + + * Remove unused library + * Git: slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+2 + + -- Jeongmo Yang Fri, 20 Jul 2012 11:56:47 +0900 + +gstreamer0.10 (0.10.36-1slp2+1) unstable; urgency=low + + * Upgrade 0.10.34 to 0.10.36 + * Git: slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.36-1slp2+1 + + -- Hyunseok Lee Wed, 27 Jun 2012 20:39:51 +0900 + +gstreamer0.10 (0.10.34-10slp2+19) unstable; urgency=low + + * [elementfactory] fix first parameter type of g_atomic_pointer_compare_and_exchange() from (gpointer) to (gpointer *) + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+19 + + -- Sangchul Lee Mon, 18 Jun 2012 18:01:25 +0900 + +gstreamer0.10 (0.10.34-10slp2+18) unstable; urgency=low + + * [baseparse] Changed baseparse to support unified reverse trickplay + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+18 + + -- Naveen Ch Mon, 02 Apr 2012 17:20:23 +0900 + +gstreamer0.10 (0.10.34-10slp2+17) unstable; urgency=low + + * [Filesink] add to get current bytes for progressive download + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+17 + + -- Younghwan Ahn Fri, 09 Mar 2012 11:46:23 +0900 + +gstreamer0.10 (0.10.34-10slp2+16) unstable; urgency=low + + * [Queue2] change high-limit/low-limit to double from int + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+16 + + -- YeJin Cho Thu, 12 Jan 2012 17:16:02 +0900 + +gstreamer0.10 (0.10.34-10slp2+15) unstable; urgency=low + + * [Queue2] Fix to add range after receiving new segment + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+15 + + -- YeJin Cho Mon, 26 Dec 2011 12:12:03 +0900 + +gstreamer0.10 (0.10.34-10slp2+14) unstable; urgency=low + + * [Queue2] Fix to drop buffers to be written before receiving the new segment event after sending seek event + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+14 + + -- YeJin Cho Wed, 21 Dec 2011 18:47:28 +0900 + +gstreamer0.10 (0.10.34-10slp2+13) unstable; urgency=low + + * [Queue2] Fix to update buffering right before sink pad is activated + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+13 + + -- YeJin Cho Thu, 17 Nov 2011 17:01:22 +0900 + +gstreamer0.10 (0.10.34-10slp2+12) unstable; urgency=low + + * [Queue2] Enable file-ring-buffer for limited memory + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+12 + + -- YeJin Cho Mon, 07 Nov 2011 18:13:35 +0900 + +gstreamer0.10 (0.10.34-10slp2+11) unstable; urgency=low + + * [Queue2] Remove unused signal + * [Queue2] Fix to update buffering message when high/low threshold are changed. + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+11 + + -- YeJin Cho Mon, 24 Oct 2011 15:01:12 +0900 + +gstreamer0.10 (0.10.34-10slp2+10) unstable; urgency=low + + * [Queue2] Remove usleep + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+10 + + -- YeJin Cho Thu, 06 Oct 2011 18:18:37 +0900 + +gstreamer0.10 (0.10.34-10slp2+9) unstable; urgency=low + + * [Queue2] Fix to file i/o mechanism for fast buffering + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+9 + + -- YeJin Cho Tue, 04 Oct 2011 21:22:41 +0900 + +gstreamer0.10 (0.10.34-10slp2+8) unstable; urgency=low + + * [Queue2] Fix to enable updated queue2 for streaming + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+8 + + -- YeJin Cho Wed, 17 Aug 2011 14:04:02 +0900 + +gstreamer0.10 (0.10.34-10slp2+7) unstable; urgency=low + + * Fix to enable GST_DISABLE_LOADSAVE to enable sami subtitle + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+7 + + -- YeJin Cho Wed, 10 Aug 2011 14:12:20 +0900 + +gstreamer0.10 (0.10.34-10slp2+6) unstable; urgency=low + + * Fix duration issue + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+6 + + -- Seungbae Shin Thu, 07 Jul 2011 15:31:42 +0900 + +gstreamer0.10 (0.10.34-10slp2+5) unstable; urgency=low + + * Rollback baseparse merge + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+5 + + -- Seungbae Shin Thu, 09 Jun 2011 14:24:02 +0900 + +gstreamer0.10 (0.10.34-10slp2+4) unstable; urgency=low + + * remove old files + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+4 + + -- Younghwan Ahn Wed, 08 Jun 2011 16:56:17 +0900 + +gstreamer0.10 (0.10.34-10slp2+3) unstable; urgency=low + + * update changelog + * Git: 165.213.180.234:slp/pkgs/g/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+3 + + -- Younghwan Ahn Tue, 07 Jun 2011 20:33:39 +0900 + +gstreamer0.10 (0.10.34-10slp2+2) unstable; urgency=low + + * fix queue2 temp for http streaming + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+2 + + -- YeJin Cho Tue, 07 Jun 2011 16:39:08 +0900 + +gstreamer0.10 (0.10.34-10slp2+1) unstable; urgency=low + + * upgrade 33 to 34 + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.34-10slp2+1 + + -- nosurprises Mon, 23 May 2011 11:59:59 +0900 + +gstreamer0.10 (0.10.33-10slp2+1) lucid; urgency=low + + * upgrade 25 to 33 + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.33-10slp2+1 + + -- Younghwan Ahn Thu, 12 May 2011 19:29:11 +0900 + +gstreamer0.10 (0.10.25-10slp2+11) unstable; urgency=low + + * Fix for as-needed + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.25-10slp2+11 + + -- Seungbae Shin Wed, 24 Nov 2010 21:02:28 +0900 + +gstreamer0.10 (0.10.25-10slp2+10) unstable; urgency=low + + * Add dbg-package, fPIC, as-needed + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.25-10slp2+10 + + -- Seungbae Shin Fri, 19 Nov 2010 11:26:34 +0900 + +gstreamer0.10 (0.10.25-10slp2+9) unstable; urgency=low + + * Add "keep-last-buffer" property to basesink for capturing last buffer + * Git: 165.213.180.234:/git/slp/pkgs/gstreamer0.10 + * Tag: gstreamer0.10_0.10.25-10slp2+9 + + -- Jeongmo Yang Wed, 25 Aug 2010 11:56:59 +0900 + +gstreamer0.10 (0.10.25-10slp2+8) unstable; urgency=low + + * remove old dlog dependency + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/gstreamer-0.10.25 + * Tag: gstreamer0.10_0.10.25-10slp2+8 + + -- YoungHwan Ahn Mon, 28 Jun 2010 15:23:18 +0900 + +gstreamer0.10 (0.10.25-10slp2+7) unstable; urgency=low + + * Call gst_base_sink_set_last_buffer with NULL after render() + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/gstreamer-0.10.25 + * Tag: gstreamer0.10_0.10.25-10slp2+7 + + -- Wonhyung Cho Wed, 09 Jun 2010 21:42:47 +0900 + +gstreamer0.10 (0.10.25-10slp2+6) unstable; urgency=low + + * Add libmm-ta-dev to dev package + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/gstreamer-0.10.25 + * Tag: gstreamer0.10_0.10.25-10slp2+6 + + -- Seungbae Shin Mon, 10 May 2010 20:51:03 +0900 + +gstreamer0.10 (0.10.25-10slp2+5) unstable; urgency=low + + * Add SDK package + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/gstreamer-0.10.25 + * Tag: gstreamer0.10_0.10.25-10slp2+5 + + -- Seungbae Shin Mon, 10 May 2010 14:05:21 +0900 + +gstreamer0.10 (0.10.25-9slp2+2) unstable; urgency=low + + * Move ta include to internal + + -- Seungbae Shin Thu, 06 May 2010 11:07:35 +0900 + +gstreamer0.10 (0.10.25-9slp2+1) unstable; urgency=low + + * Replace ta-dev with ta-sdk-dev package + + -- Seungbae Shin Tue, 04 May 2010 20:04:04 +0900 + +gstreamer0.10 (0.10.25-9slp2+0) unstable; urgency=low + + * Change package naming rule + + -- Seungbae Shin Thu, 25 Mar 2010 15:06:39 +0900 + +gstreamer0.10 (0.10.25-9) unstable; urgency=low + + * Modify gstbasesrc to make base loop not compete with state change with _MMCAMCORDER_MODIFIED_DQBUF feature + + -- Wonhyung Cho Mon, 22 Mar 2010 13:55:56 +0900 + +gstreamer0.10 (0.10.25-8) unstable; urgency=low + + * Email violation + + -- Wonhyung Cho Fri, 05 Feb 2010 19:30:02 +0900 + +gstreamer0.10 (0.10.25-7) unstable; urgency=low + + * Fix seg fault error while on capturing + + -- Wonhyung Cho Tue, 02 Feb 2010 14:34:44 +0900 + +gstreamer0.10 (0.10.25-6) unstable; urgency=low + + * [H0100077084] Fix audio breaks bug when pause->resume + + -- Shin Seung Bae Wed, 20 Jan 2010 20:39:39 +0900 + +gstreamer0.10 (0.10.25-5) unstable; urgency=low + + * Remove bison check in build-dep section + + -- Shin Seung Bae Tue, 29 Dec 2009 11:34:59 +0900 + +gstreamer0.10 (0.10.25-4) unstable; urgency=low + + * Fix wrong dependancy about libmm-ta + + -- Wonhyung Tue, 22 Dec 2009 18:24:30 +0900 + +gstreamer0.10 (0.10.25-3) unstable; urgency=low + + * Enable empty-buffers property of gstqueue + + -- Wonhyung Tue, 22 Dec 2009 17:52:38 +0900 + +gstreamer0.10 (0.10.25-2) unstable; urgency=low + + * Removed unnecessary folder 'debian_opensrc' + + -- Myungjae Lee Thu, 27 Nov 2009 15:36:00 +0900 + +gstreamer0.10 (0.10.25-1) unstable; urgency=low + + * Changed initial version from 0.10.22 to 0.10.25 + + -- Myungjae Lee Thu, 13 Nov 2009 13:31:00 +0900 + +gstreamer0.10 (0.10.22-2) unstable; urgency=low + + * Uploaded source files + + -- Myungjae Lee Thu, 12 Nov 2009 19:44:11 +0900 + +gstreamer0.10 (0.10.22-1) unstable; urgency=low + + * Initial release. + + -- Myungjae Lee Thu, 12 Nov 2009 18:51:00 +0900 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d9a9887 --- /dev/null +++ b/debian/control @@ -0,0 +1,110 @@ +Source: gstreamer0.10 +Section: libs +Priority: optional +Maintainer: Shin Seung Bae , JongHyuk Choi +Uploaders: Shin Seung Bae , JongHyuk Choi , Hyunseok Lee , YoungHwan Ahn , Jeongmo Yang , Naveen Ch +Build-Depends: debhelper (>= 5), + autotools-dev, + libxml2-dev (>= 2.6.0), + zlib1g-dev (>= 1:1.1.4), + libglib2.0-dev (>= 2.12), + pkg-config (>= 0.11.0), + libmm-ta-dev +Standards-Version: 3.8.0 + +Package: libgstreamer0.10-0 +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, libmm-ta +Suggests: gstreamer0.10-tools, + gstreamer0.10-plugins +Description: Core GStreamer libraries and elements + GStreamer is a streaming media framework, based on graphs of filters + which operate on media data. Applications using this library can do + anything from real-time sound processing to playing videos, and just + about anything else media-related. Its plugin-based architecture means + that new data types or processing capabilities can be added simply by + installing new plug-ins. + . + This package contains the core library and elements. + +Package: libgstreamer0.10-dev +XB-Public-Package: no +Architecture: any +Section: libdevel +Depends: libmm-ta-dev, libgstreamer0.10-sdk-dev +Description: GStreamer core SDK development files + GStreamer is a streaming media framework, based on graphs of filters + which operate on media data. Applications using this library can do + anything from real-time sound processing to playing videos, and just + about anything else media-related. Its plugin-based architecture means + that new data types or processing capabilities can be added simply by + installing new plug-ins. + . + This package contains SDK development files for the core library and + elements. + + +Package: libgstreamer0.10-sdk-dev +Architecture: any +Section: libdevel +Depends: libgstreamer0.10-0 (= ${binary:Version}), + libc6-dev | libc-dev, + pkg-config, + libglib2.0-dev, + libxml2-dev, + libmm-ta-sdk-dev, + ${shlibs:Depends} +Replaces: gstreamer-tools (<< 0.10.20-2) +Recommends: debhelper +Suggests: gstreamer0.10-doc +Description: GStreamer core development files + GStreamer is a streaming media framework, based on graphs of filters + which operate on media data. Applications using this library can do + anything from real-time sound processing to playing videos, and just + about anything else media-related. Its plugin-based architecture means + that new data types or processing capabilities can be added simply by + installing new plug-ins. + . + This package contains development files for the core library and + elements. + +Package: gstreamer0.10-tools +Architecture: any +Section: utils +Depends: ${shlibs:Depends}, + pkg-config, + libgstreamer0.10-0 (>= 0.10.21.3) +Suggests: gstreamer0.10-plugins-base +Description: Tools for use with GStreamer + GStreamer is a streaming media framework, based on graphs of filters + which operate on media data. Applications using this library can do + anything from real-time sound processing to playing videos, and just + about anything else media-related. Its plugin-based architecture means + that new data types or processing capabilities can be added simply by + installing new plug-ins. + . + This package contains versioned command-line tools for GStreamer. + +Package: gstreamer-tools +Architecture: any +Section: utils +Depends: ${shlibs:Depends}, + gstreamer0.10-tools | gstreamer0.8-tools +Conflicts: gstreamer0.8-tools (<< 0.8.11-2) +Description: Tools for use with GStreamer + GStreamer is a streaming media framework, based on graphs of filters + which operate on media data. Applications using this library can do + anything from real-time sound processing to playing videos, and just + about anything else media-related. Its plugin-based architecture means + that new data types or processing capabilities can be added simply by + installing new plug-ins. + . + This package contains unversioned command-line tools for GStreamer + that work with different major/minor versions of GStreamer. + +Package: libgstreamer0.10-0-dbg +Section: debug +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libgstreamer0.10-0 (= ${Source-Version}) +Description: Core GStreamer libraries and elements (unstripped) diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..b70e835 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,31 @@ +This package was debianized by David I. Lehn on +Mon, 15 Jan 2001 18:21:37 -0500. + +It was downloaded from . + +Upstream Authors: + + Erik Walthinsen + Wim Taymans + Richard Boulton + and many more... + +Copyright: + + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian GNU/Linux systems, the complete text of the GNU Lesser General +Public License can be found in `/usr/share/common-licenses/LGPL'. + diff --git a/debian/gstreamer-tools.install b/debian/gstreamer-tools.install new file mode 100644 index 0000000..3b6c713 --- /dev/null +++ b/debian/gstreamer-tools.install @@ -0,0 +1,2 @@ +usr/bin/gst-inspect +usr/bin/gst-launch diff --git a/debian/gstreamer0.10-tools.install b/debian/gstreamer0.10-tools.install new file mode 100644 index 0000000..e252f95 --- /dev/null +++ b/debian/gstreamer0.10-tools.install @@ -0,0 +1,2 @@ +usr/bin/gst-inspect-0.10 +usr/bin/gst-launch-0.10 diff --git a/debian/libgstreamer0.10-0.install b/debian/libgstreamer0.10-0.install new file mode 100644 index 0000000..6f13b2b --- /dev/null +++ b/debian/libgstreamer0.10-0.install @@ -0,0 +1,2 @@ +usr/lib/gstreamer-0.10/*.so* +usr/lib/*.so* diff --git a/debian/libgstreamer0.10-dev.install b/debian/libgstreamer0.10-dev.install new file mode 100644 index 0000000..e43b95c --- /dev/null +++ b/debian/libgstreamer0.10-dev.install @@ -0,0 +1 @@ +usr/include diff --git a/debian/libgstreamer0.10-sdk-dev.install b/debian/libgstreamer0.10-sdk-dev.install new file mode 100644 index 0000000..bc4f836 --- /dev/null +++ b/debian/libgstreamer0.10-sdk-dev.install @@ -0,0 +1,4 @@ +usr/lib/*.{a,la} +usr/lib/gstreamer-0.10/*.{a,la} +usr/lib/pkgconfig +usr/share/aclocal diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..dcd4191 --- /dev/null +++ b/debian/rules @@ -0,0 +1,113 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# Include dpatch stuff +include /usr/share/dpatch/dpatch.make + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +# fixit : need to check +CFLAGS += -Wall -g -fPIC \ + -DGST_EXT_AV_RECORDING \ + -DGST_EXT_QUEUE_ENHANCEMENT \ + -DGST_EXT_CURRENT_BYTES \ + -D_VSP_SPEED_ + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +# shared library versions, option 1 +version=0.10.22 +major=1 +# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so +#version=`ls src/.libs/lib*.so.* | \ +# awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` +#major=`ls src/.libs/lib*.so.* | \ +# awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` + +LDFLAGS += -Wl,--hash-style=both -Wl,--as-needed + +config.status: + dh_testdir + ./autogen.sh + + ./configure --prefix=/usr \ + --disable-valgrind \ + --without-check \ + --disable-static \ + --disable-rpath \ + --disable-libtool-lock \ + --disable-alloc-trace \ + --disable-gcov \ + --disable-nls \ + --disable-examples \ + --disable-tests \ + --disable-failing-tests \ + --disable-docbook \ + --disable-gtk-doc \ + --disable-registry-update \ + --disable-loadsave \ + --with-html-dir=/tmp/dump \ + $(CONFIGURE_OPTIONS) \ + CFLAGS="$(CFLAGS)" \ + LDFLAGS="$(LDFLAGS)" + + +build: build-stamp +build-stamp: patch-stamp config.status + dh_testdir + + $(MAKE) + touch build-stamp + +clean: clean1 unpatch +clean1: + dh_testdir + dh_testroot + rm -f build-stamp patch-stamp + + -$(MAKE) distclean + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/tmp + $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_install --sourcedir=debian/tmp --list-missing + dh_link + dh_strip --dbg-package=libgstreamer0.10-0-dbg + dh_compress + dh_fixperms + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install patch unpatch clean clean1 diff --git a/gst/Makefile.am b/gst/Makefile.am old mode 100644 new mode 100755 index b949b93..9ace101 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -128,15 +128,20 @@ libgstreamer_@GST_MAJORMINOR@_la_CFLAGS = \ -DGST_MAJORMINOR=\""$(GST_MAJORMINOR)"\" \ -DGST_DISABLE_DEPRECATED \ $(VALGRIND_CFLAGS) \ + $(DLOG_CFLAGS) \ $(GST_ALL_CFLAGS) +if USE_DLOG +libgstreamer_@GST_MAJORMINOR@_la_CFLAGS += -DUSE_DLOG +endif + libgstreamer_@GST_MAJORMINOR@_la_LIBADD = \ $(GST_PARSE_LA) \ $(GST_ALL_LIBS) \ $(WIN32_LIBS) \ $(XML_LIBS) \ $(LIBM) \ - -lmm_ta + $(DLOG_LIBS) libgstreamer_@GST_MAJORMINOR@_la_LDFLAGS = \ $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) diff --git a/gst/gst.c b/gst/gst.c index 4b56ee9..9e6c293 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -118,8 +118,6 @@ #include /* for LC_ALL */ #include "gst.h" -#include - #define GST_CAT_DEFAULT GST_CAT_GST_INIT @@ -498,9 +496,6 @@ gst_init (int *argc, char **argv[]) { GError *err = NULL; - MMTA_INIT(); - -__ta__("gst_init", if (!gst_init_check (argc, argv, &err)) { g_print ("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); @@ -509,8 +504,6 @@ __ta__("gst_init", } exit (1); } -) - } /** @@ -1135,8 +1128,6 @@ gst_deinit (void) gst_deinitialized = TRUE; GST_INFO ("deinitialized GStreamer"); - MMTA_RELEASE(); - } /** diff --git a/gst/gstbin.c b/gst/gstbin.c index 479917f..4b32bf6 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -2802,13 +2802,26 @@ bin_push_state_continue (BinContinueData * data) { GstBinClass *klass; GstBin *bin; +#ifdef GST_EXT_BASIC_MODIFICATION + int ret = 0; + GError *error = NULL; +#endif /* GST_EXT_BASIC_MODIFICATION */ /* ref was taken */ bin = data->bin; klass = GST_BIN_GET_CLASS (bin); GST_DEBUG_OBJECT (bin, "pushing continue on thread pool"); +#ifdef GST_EXT_BASIC_MODIFICATION + ret = g_thread_pool_push (klass->pool, data, &error); + GST_DEBUG_OBJECT (bin, "g_thread_pool_push ret %d", ret); + if (!ret && error) { + GST_ERROR_OBJECT (bin, "error message %s", error->message); + g_error_free(error); + } +#else /* GST_EXT_BASIC_MODIFICATION */ g_thread_pool_push (klass->pool, data, NULL); +#endif /* GST_EXT_BASIC_MODIFICATION */ } /* an element started an async state change, if we were not busy with a state diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index edc0a6e..9a57f46 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -127,6 +127,9 @@ #include "gstutils.h" #include "gstminiobject.h" #include "gstversion.h" +#ifdef GST_EXT_AV_RECORDING +#include "gstvalue.h" +#endif /* GST_EXT_AV_RECORDING */ struct _GstBufferPrivate { @@ -703,6 +706,34 @@ GstBuffer * gst_buffer_make_metadata_writable (GstBuffer * buf) { GstBuffer *ret; +#ifdef GST_EXT_AV_RECORDING + GstStructure *structure = NULL; + guint32 format = 0; + GstCaps *buf_caps = gst_buffer_get_caps(buf); + + if (buf_caps) { + structure = gst_caps_get_structure(buf_caps, 0); + if (structure) { + gst_structure_get_fourcc(structure, "format", &format); + if (format == GST_MAKE_FOURCC('S', 'R', '3', '2') || + format == GST_MAKE_FOURCC('I', 'T', 'L', 'V') || + format == GST_MAKE_FOURCC('S', '4', '2', '0') || + format == GST_MAKE_FOURCC('S', 'U', 'Y', 'V') || + format == GST_MAKE_FOURCC('S', 'Y', 'V', 'Y') || + format == GST_MAKE_FOURCC('S', 'N', '2', '1') || + format == GST_MAKE_FOURCC('S', 'T', '1', '2') || + format == GST_MAKE_FOURCC('S', 'N', '1', '2') || + format == GST_MAKE_FOURCC('S', 'V', '1', '2')) { + GST_CAT_INFO(GST_CAT_BUFFER, "It's zero copy buffer. return itself."); + gst_caps_unref(buf_caps); + buf_caps = NULL; + return buf; + } + } + gst_caps_unref(buf_caps); + buf_caps = NULL; + } +#endif /* GST_EXT_AV_RECORDING */ if (gst_buffer_is_metadata_writable (buf)) { ret = buf; diff --git a/gst/gstcaps.c b/gst/gstcaps.c old mode 100644 new mode 100755 index ef3f8ff..cda5204 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -432,6 +432,11 @@ gst_caps_unref (GstCaps * caps) GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) - 1); #endif + if (GST_CAPS_REFCOUNT_VALUE (caps) > 10000) { + GST_WARNING(" refcount = %d \n",GST_CAPS_REFCOUNT_VALUE (caps)); + return; + } + g_return_if_fail (GST_CAPS_REFCOUNT_VALUE (caps) > 0); /* if we ended up with the refcount at zero, free the caps */ diff --git a/gst/gstelement.c b/gst/gstelement.c index 4d0af67..28fc686 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -100,8 +100,6 @@ #include "gst-i18n-lib.h" #include "glib-compat-private.h" -#include - /* Element signals and args */ enum { @@ -2295,13 +2293,10 @@ gst_element_get_state (GstElement * element, oclass = GST_ELEMENT_GET_CLASS (element); sprintf( szMsg, "gst_element_get_state (%s)", GST_ELEMENT_NAME(element) ); - MMTA_ACUM_ITEM_BEGIN(szMsg, FALSE ); if (oclass->get_state) result = (oclass->get_state) (element, state, pending, timeout); - MMTA_ACUM_ITEM_END( szMsg, FALSE ); - return result; } @@ -2623,15 +2618,12 @@ gst_element_set_state (GstElement * element, GstState state) g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); sprintf(szDebugMsg, "set %s state %s to %s", GST_ELEMENT_NAME (element), gst_element_state_get_name(GST_STATE (element)), gst_element_state_get_name(state) ); - MMTA_ACUM_ITEM_BEGIN(szDebugMsg, FALSE); oclass = GST_ELEMENT_GET_CLASS (element); if (oclass->set_state) result = (oclass->set_state) (element, state); - MMTA_ACUM_ITEM_END(szDebugMsg, FALSE); - return result; } diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index e7e6f9b..a74183c 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -68,8 +68,6 @@ #include "glib-compat-private.h" -#include - GST_DEBUG_CATEGORY_STATIC (element_factory_debug); #define GST_CAT_DEFAULT element_factory_debug @@ -362,9 +360,6 @@ gst_element_factory_create (GstElementFactory * factory, const gchar * name) g_return_val_if_fail (factory != NULL, NULL); -__ta__(__tafmt__("Creating Element %s(name:%s)", GST_PLUGIN_FEATURE_NAME (factory), name), - - newfactory = GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE (factory))); @@ -406,8 +401,6 @@ __ta__(__tafmt__("Creating Element %s(name:%s)", GST_PLUGIN_FEATURE_NAME (factor GST_DEBUG ("created element \"%s\"", GST_PLUGIN_FEATURE_NAME (factory)); -) // __ta__ - return element; /* ERRORS */ diff --git a/gst/gstinfo.c b/gst/gstinfo.c index 266feed..1cc1397 100644 --- a/gst/gstinfo.c +++ b/gst/gstinfo.c @@ -215,6 +215,14 @@ dladdr (void *address, Dl_info * dl) #endif /* __sgi__ */ #endif +#if defined(USE_DLOG) && defined(GST_EXT_BASIC_MODIFICATION) +#include + +//#define _SLOG(class, format, arg...) \ + //(SLOG(class, "GST_LOG" ,"%s:%s(%d)>"format, __MODULE__, __func__, __LINE__, ##arg)) +#endif + + static void gst_debug_reset_threshold (gpointer category, gpointer unused); static void gst_debug_reset_all_thresholds (void); @@ -974,12 +982,23 @@ gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level, levelcolor = levelcolormap[level]; #define PRINT_FMT " %s"PID_FMT"%s "PTR_FMT" %s%s%s %s"CAT_FMT"%s %s\n" + +#if defined(USE_DLOG) && defined(GST_EXT_BASIC_MODIFICATION) + SLOG(LOG_WARN, "GST_LOG", + "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed), + pidcolor, pid, clear, g_thread_self (), levelcolor, + gst_debug_level_get_name (level), clear, color, + gst_debug_category_get_name (category), file, line, function, obj, + clear, gst_debug_message_get (message)); +#else fprintf (log_file, "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed), pidcolor, pid, clear, g_thread_self (), levelcolor, gst_debug_level_get_name (level), clear, color, gst_debug_category_get_name (category), file, line, function, obj, clear, gst_debug_message_get (message)); fflush (log_file); +#endif + #undef PRINT_FMT g_free (color); #else @@ -988,6 +1007,7 @@ gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level, * thing. */ static GStaticMutex win_print_mutex = G_STATIC_MUTEX_INIT; const gint clear = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + #define SET_COLOR(c) G_STMT_START { \ if (log_file == stderr) \ SetConsoleTextAttribute (GetStdHandle (STD_ERROR_HANDLE), (c)); \ @@ -1023,11 +1043,22 @@ gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level, } else { /* no color, all platforms */ #define PRINT_FMT " "PID_FMT" "PTR_FMT" %s "CAT_FMT" %s\n" + + /* Tizen doesn't care about Win32 */ +#if defined(USG_DLOG) && defined(GST_EXT_BASIC_MODIFICATION) && !defined(G_OS_WIN32) + SLOG(LOG_WARN, "GST_LOG", + "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed), + pid, g_thread_self (), gst_debug_level_get_name (level), + gst_debug_category_get_name (category), file, line, function, obj, + gst_debug_message_get (message)); +#else fprintf (log_file, "%" GST_TIME_FORMAT PRINT_FMT, GST_TIME_ARGS (elapsed), pid, g_thread_self (), gst_debug_level_get_name (level), gst_debug_category_get_name (category), file, line, function, obj, gst_debug_message_get (message)); fflush (log_file); +#endif + #undef PRINT_FMT } diff --git a/gst/gstplugin.c b/gst/gstplugin.c index 81cf0eb..02e5cc9 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -67,8 +67,6 @@ #include "glib-compat-private.h" #include -#include - #define GST_CAT_DEFAULT GST_CAT_PLUGIN_LOADING @@ -735,8 +733,6 @@ gst_plugin_load_file (const gchar * filename, GError ** error) } } -__ta__(__tafmt__("load plugin %s", filename), - GST_CAT_DEBUG (GST_CAT_PLUGIN_LOADING, "attempt to load plugin \"%s\"", filename); @@ -867,8 +863,6 @@ __ta__(__tafmt__("load plugin %s", filename), gst_default_registry_add_plugin (plugin); } -) //__ta__ - g_static_mutex_unlock (&gst_plugin_loading_mutex); return plugin; diff --git a/gst/gststructure.c b/gst/gststructure.c index 23c54b3..2def8de 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -819,6 +819,10 @@ gst_structure_id_get_field (const GstStructure * structure, GQuark field_id) GstStructureField *field; guint i, len; +#ifdef GST_EXT_BASIC_MODIFICATION + g_return_val_if_fail (structure != NULL, NULL); + g_return_val_if_fail (structure->fields != NULL, NULL); +#endif len = structure->fields->len; for (i = 0; i < len; i++) { diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 2c71489..9499f1d 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -74,8 +74,23 @@ struct _GstSystemClockPrivate LARGE_INTEGER start; LARGE_INTEGER frequency; #endif /* G_OS_WIN32 */ + + wait_jitter_adjust_func wait_jitter_adjust; + gpointer adjust_user_data; + wait_jitter_adjust_func wait_jitter_revert; + gpointer revert_user_data; }; +/* consider after adjust , no need to wait again */ +#define GST_SYSTEM_CLOCK_WAIT_ADJUST(clock) \ + if(clock->priv->wait_jitter_adjust) { \ + clock->priv->wait_jitter_adjust(clock, clock->priv->adjust_user_data); \ + wait_twice = FALSE; } + +#define GST_SYSTEM_CLOCK_WAIT_REVERT(clock) \ + if(clock->priv->wait_jitter_revert) \ + clock->priv->wait_jitter_revert(clock, clock->priv->revert_user_data); + #define GST_SYSTEM_CLOCK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SYSTEM_CLOCK, \ GstSystemClockPrivate)) @@ -173,6 +188,9 @@ gst_system_clock_init (GstSystemClock * clock) clock->priv->clock_type = DEFAULT_CLOCK_TYPE; clock->priv->timer = gst_poll_new_timer (); + gst_system_clock_wait_adjust(clock, NULL, NULL); + gst_system_clock_wait_revert(clock, NULL, NULL); + #ifdef G_OS_WIN32 QueryPerformanceFrequency (&clock->priv->frequency); /* can be 0 if the hardware does not have hardware support */ @@ -581,13 +599,17 @@ gst_system_clock_id_wait_jitter_unlocked (GstClock * clock, GstClockTime entryt, now; GstClockTimeDiff diff; GstClockReturn status; + gboolean wait_twice = TRUE; if (G_UNLIKELY (GET_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)) return GST_CLOCK_UNSCHEDULED; /* need to call the overridden method because we want to sync against the time * of the clock, whatever the subclass uses as a clock. */ + + GST_SYSTEM_CLOCK_WAIT_ADJUST(sysclock); now = gst_clock_get_time (clock); + GST_SYSTEM_CLOCK_WAIT_REVERT(sysclock); /* get the time of the entry */ entryt = GST_CLOCK_ENTRY_TIME (entry); @@ -677,8 +699,11 @@ gst_system_clock_id_wait_jitter_unlocked (GstClock * clock, /* reschedule if gst_poll_wait returned early or we have to reschedule after * an unlock*/ - now = gst_clock_get_time (clock); - diff = GST_CLOCK_DIFF (now, entryt); + if(wait_twice) { + now = gst_clock_get_time (clock); + diff = GST_CLOCK_DIFF (now, entryt); + } else + diff = 0; if (diff <= 0) { /* timeout, this is fine, we can report success now */ @@ -879,3 +904,27 @@ gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry) } GST_OBJECT_UNLOCK (clock); } + +void +gst_system_clock_wait_adjust(GstClock *clock, + wait_jitter_adjust_func wait_jitter_adjust, gpointer user_data) +{ + GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST(clock); + + GST_OBJECT_LOCK(sysclock); + sysclock->priv->wait_jitter_adjust = wait_jitter_adjust; + sysclock->priv->adjust_user_data = user_data; + GST_OBJECT_UNLOCK(sysclock); +} + +void +gst_system_clock_wait_revert(GstClock *clock, + wait_jitter_adjust_func wait_jitter_revert, gpointer user_data) +{ + GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST(clock); + + GST_OBJECT_LOCK(sysclock); + sysclock->priv->wait_jitter_revert = wait_jitter_revert; + sysclock->priv->revert_user_data = user_data; + GST_OBJECT_UNLOCK(sysclock); +} diff --git a/gst/gstsystemclock.h b/gst/gstsystemclock.h index 4f372de..5142494 100644 --- a/gst/gstsystemclock.h +++ b/gst/gstsystemclock.h @@ -80,9 +80,18 @@ struct _GstSystemClockClass { gpointer _gst_reserved[GST_PADDING]; }; -GType gst_system_clock_get_type (void); +GType gst_system_clock_get_type (void); -GstClock* gst_system_clock_obtain (void); +GstClock* gst_system_clock_obtain (void); + + +typedef void (*wait_jitter_adjust_func)(GstClock *clock, gpointer user_data); + +void gst_system_clock_wait_adjust(GstClock *clock, + wait_jitter_adjust_func wait_jitter_adjust, gpointer user_data); + +void gst_system_clock_wait_revert(GstClock *clock, + wait_jitter_adjust_func wait_jitter_revert, gpointer user_data); G_END_DECLS diff --git a/gstreamer-tools.manifest b/gstreamer-tools.manifest new file mode 100755 index 0000000..1b29b0f --- /dev/null +++ b/gstreamer-tools.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gstreamer.manifest b/gstreamer.manifest new file mode 100755 index 0000000..cecb82f --- /dev/null +++ b/gstreamer.manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index 5ca48a9..fb7ff95 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -210,7 +210,12 @@ #define GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC (1 << 0) +#ifdef GST_EXT_BASEPARSER_MODIFICATION +#define MIN_FRAMES_TO_POST_BITRATE 1 +#else #define MIN_FRAMES_TO_POST_BITRATE 10 +#endif + #define TARGET_DIFFERENCE (20 * GST_SECOND) GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug); @@ -330,6 +335,39 @@ struct _GstBaseParsePrivate gboolean detecting; GList *detect_buffers; guint detect_buffers_size; +#ifdef GST_EXT_BASEPARSER_MODIFICATION + GstActivateMode expected_pad_mode; /* to get pad mode early */ + gboolean first_frame; /* check first frame in base parser */ + gint64 remove_from_total; /* remove zero padding */ + gboolean accurate_index_seek; +#endif + +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + /* added for ALP mode (using 32KB Gstbuffer) */ + guint32 alp_mp3_mode; + + guint32 alp_seek_on; + /* ALP - for frame number */ + guint32 alp_frame_1st; + guint32 alp_frame_count; + guint32 alp_frame_in_buffer; + guint32 alp_buffer_count; + guint32 alp_frame_avgbitrate; + /* ALP - for duration */ + guint64 alp_duration_frame; + guint64 alp_duration_buffer; + guint64 alp_duration_buf_total; + guint64 alp_estimated_duration; + /* ALP - for position and byte count */ + guint32 alp_size_frame_total; + guint32 alp_size_buf_one; + guint64 alp_size_buf_total; + guint32 alp_size_frame_1st; +#endif +#ifdef GST_EXT_BASEPARSE_ENABLE_WFD + /* added for wi-fi display mode */ + gboolean wfd_mode; +#endif }; typedef struct _GstBaseParseSeek @@ -581,6 +619,13 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass) parse->priv->adapter = gst_adapter_new (); parse->priv->pad_mode = GST_ACTIVATE_NONE; +#ifdef GST_EXT_BASEPARSER_MODIFICATION + parse->priv->expected_pad_mode = GST_ACTIVATE_NONE; +#endif + +#ifdef GST_EXT_BASEPARSE_ENABLE_WFD + parse->priv->wfd_mode = FALSE; +#endif #if !GLIB_CHECK_VERSION (2, 31, 0) g_static_mutex_init (&parse->priv->index_lock); @@ -756,6 +801,30 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->last_ts = GST_CLOCK_TIME_NONE; parse->priv->last_offset = 0; +#ifdef GST_EXT_BASEPARSER_MODIFICATION /* to do not calculate zero padding or something */ + parse->priv->first_frame = TRUE; + parse->priv->remove_from_total = 0; + parse->priv->accurate_index_seek = TRUE; +#endif + +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + parse->priv->alp_mp3_mode = 0; + parse->priv->alp_seek_on = 0; + + parse->priv->alp_frame_1st = 0; + parse->priv->alp_frame_count = 0; + parse->priv->alp_frame_in_buffer = 0; + parse->priv->alp_buffer_count = 0; + + parse->priv->alp_duration_frame = 0; + parse->priv->alp_duration_buffer = 0; + parse->priv->alp_duration_buf_total = 0; + + parse->priv->alp_size_frame_total = 0; + parse->priv->alp_size_buf_one = 0; + parse->priv->alp_size_buf_total = 0; + parse->priv->alp_size_frame_1st = 0; +#endif if (parse->priv->pending_segment) { gst_event_unref (parse->priv->pending_segment); @@ -1093,6 +1162,12 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) parse->priv->last_ts = GST_CLOCK_TIME_NONE; parse->priv->frame._private_flags |= GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC; +#ifdef GST_EXT_BASEPARSE_ENABLE_WFD + if (parse->priv->wfd_mode) { + parse->priv->offset = 0; + parse->priv->sync_offset = 0; + } +#endif gst_base_parse_frame_free (&parse->priv->frame); break; @@ -1231,8 +1306,30 @@ gst_base_parse_convert_default (GstBaseParse * parse, if (!parse->priv->framecount) return FALSE; +#ifdef GST_EXT_BASEPARSER_MODIFICATION +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_frame_1st) { + /* For duration, Estimation of spf using 1st frame */ + duration = parse->priv->alp_duration_frame / GST_USECOND; + bytes = parse->priv->alp_size_frame_1st; + GST_DEBUG_OBJECT (parse, "bytes (%" G_GINT64_FORMAT ") frame_duration (%" G_GINT64_FORMAT ")", bytes, duration); + } else { + duration = parse->priv->acc_duration / GST_USECOND; + bytes = parse->priv->bytecount; + } +#else + duration = parse->priv->acc_duration / GST_USECOND; + bytes = parse->priv->bytecount; +#endif +#else duration = parse->priv->acc_duration / GST_MSECOND; bytes = parse->priv->bytecount; +#endif + +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + GST_DEBUG_OBJECT (parse, "duration (%" G_GINT64_FORMAT ") <-- acc_duration (%" G_GINT64_FORMAT ")", duration, parse->priv->acc_duration); + GST_DEBUG_OBJECT (parse, "bytecount (%" G_GINT64_FORMAT ") framecount (%" G_GINT64_FORMAT ")", bytes, parse->priv->framecount); +#endif if (G_UNLIKELY (!duration || !bytes)) return FALSE; @@ -1241,7 +1338,13 @@ gst_base_parse_convert_default (GstBaseParse * parse, if (dest_format == GST_FORMAT_TIME) { /* BYTES -> TIME conversion */ GST_DEBUG_OBJECT (parse, "converting bytes -> time"); +#ifdef GST_EXT_BASEPARSER_MODIFICATION + src_value = src_value - parse->priv->remove_from_total; +#endif *dest_value = gst_util_uint64_scale (src_value, duration, bytes); +#ifdef GST_EXT_BASEPARSER_MODIFICATION + *dest_value /= GST_USECOND; +#endif *dest_value *= GST_MSECOND; GST_DEBUG_OBJECT (parse, "conversion result: %" G_GINT64_FORMAT " ms", *dest_value / GST_MSECOND); @@ -1250,8 +1353,11 @@ gst_base_parse_convert_default (GstBaseParse * parse, } else if (src_format == GST_FORMAT_TIME) { if (dest_format == GST_FORMAT_BYTES) { GST_DEBUG_OBJECT (parse, "converting time -> bytes"); - *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes, - duration); +#ifdef GST_EXT_BASEPARSER_MODIFICATION + *dest_value = gst_util_uint64_scale (src_value / GST_USECOND, bytes, duration); +#else + *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes, duration); +#endif GST_DEBUG_OBJECT (parse, "time %" G_GINT64_FORMAT " ms in bytes = %" G_GINT64_FORMAT, src_value / GST_MSECOND, *dest_value); @@ -1301,6 +1407,13 @@ gst_base_parse_update_duration (GstBaseParse * baseparse) gst_message_new_duration (GST_OBJECT (parse), GST_FORMAT_TIME, dest_value)); parse->priv->estimated_drift = 0; +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + parse->priv->alp_estimated_duration = dest_value; + GST_INFO_OBJECT (parse, "[message] dest_value(%" GST_TIME_FORMAT") estimated duration to (%" G_GUINT64_FORMAT")", + GST_TIME_ARGS (dest_value), (parse->priv->estimated_duration)); + } +#endif } parse->priv->estimated_duration = dest_value; GST_LOG_OBJECT (parse, @@ -1328,7 +1441,20 @@ gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min, if (taglist == NULL) taglist = gst_tag_list_new (); - parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate; +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_frame_1st) { + if (parse->priv->bitrate) { + parse->priv->avg_bitrate = parse->priv->bitrate; + } else { + parse->priv->posted_avg_bitrate = parse->priv->alp_frame_avgbitrate; + parse->priv->avg_bitrate = parse->priv->alp_frame_avgbitrate; + } + } else { + parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate; + } +#else + parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate; +#endif gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, parse->priv->avg_bitrate, NULL); } @@ -1668,16 +1794,27 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, } /* some one-time start-up */ +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + if (parse->priv->alp_frame_1st) { //[need again check] parse->priv->framecount =0 + gst_base_parse_check_seekability (parse); + gst_base_parse_check_upstream (parse); + } + } else { + if (G_UNLIKELY (!parse->priv->framecount)) { + gst_base_parse_check_seekability (parse); + gst_base_parse_check_upstream (parse); + } + } +#else if (G_UNLIKELY (!parse->priv->framecount)) { gst_base_parse_check_seekability (parse); gst_base_parse_check_upstream (parse); } +#endif - GST_LOG_OBJECT (parse, - "parsing frame at offset %" G_GUINT64_FORMAT - " (%#" G_GINT64_MODIFIER "x) of size %d", - GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer), - GST_BUFFER_SIZE (buffer)); + GST_LOG_OBJECT (parse, "parsing frame at offset %" G_GUINT64_FORMAT " (%#" G_GINT64_MODIFIER "x) of size %d", + GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer)); /* use default handler to provide initial (upstream) metadata */ gst_base_parse_parse_frame (parse, frame); @@ -1690,6 +1827,14 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, /* subclass must play nice */ g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); +#ifdef GST_EXT_BASEPARSER_MODIFICATION + if (parse->priv->first_frame) { + parse->priv->remove_from_total = GST_BUFFER_OFFSET (buffer); + GST_DEBUG_OBJECT (parse, "first frame has offset %" G_GINT64_FORMAT ". remove from total", parse->priv->remove_from_total); + parse->priv->first_frame = FALSE; + } +#endif + /* check if subclass/format can provide ts. * If so, that allows and enables extra seek and duration determining options */ if (G_UNLIKELY (parse->priv->first_frame_offset < 0 && ret == GST_FLOW_OK)) { @@ -1719,10 +1864,32 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, /* again use default handler to add missing metadata; * we may have new information on frame properties */ gst_base_parse_parse_frame (parse, frame); - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && - GST_BUFFER_DURATION_IS_VALID (buffer)) { - parse->priv->next_ts = - GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); + +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + if (parse->priv->alp_mp3_mode) { + GST_INFO_OBJECT (parse, "framecount(%" G_GINT64_FORMAT "): next_ts(%" GST_TIME_FORMAT ") frame_duration(%" GST_TIME_FORMAT ")", + parse->priv->framecount, GST_TIME_ARGS(parse->priv->next_ts), GST_TIME_ARGS(parse->priv->frame_duration)); + } +#endif + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_BUFFER_DURATION_IS_VALID (buffer)) { +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + /*push_frame --> move to here for SEEK test */ + GST_BUFFER_TIMESTAMP (buffer) = parse->priv->alp_duration_buf_total; + GST_BUFFER_DURATION (buffer) = parse->priv->alp_duration_buffer; + } +#endif + parse->priv->next_ts = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); + + +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + if (parse->priv->alp_mp3_mode) { + GST_INFO_OBJECT (parse, "Update : next_ts(%" GST_TIME_FORMAT ") = timestamp(%" GST_TIME_FORMAT ") + duration(%" GST_TIME_FORMAT ")", + GST_TIME_ARGS(parse->priv->next_ts), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS( GST_BUFFER_DURATION (buffer))); + } +#endif + } else { /* we lost track, do not produce bogus time next time around * (probably means parser subclass has given up on parsing as well) */ @@ -1730,11 +1897,29 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, parse->priv->next_ts = GST_CLOCK_TIME_NONE; } - if (parse->priv->upstream_seekable && parse->priv->exact_position && - GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) - gst_base_parse_add_index_entry (parse, offset, - GST_BUFFER_TIMESTAMP (buffer), - !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + /* for NEXT Play */ + if (parse->priv->alp_seek_on) { + offset = parse->priv->alp_size_buf_total; + parse->priv->alp_seek_on = 0; + } + if (parse->priv->upstream_seekable && parse->priv->exact_position && GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + gst_base_parse_add_index_entry (parse, offset, parse->priv->alp_duration_buf_total, + !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE); + } + } else { + if (parse->priv->upstream_seekable && parse->priv->exact_position && GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + gst_base_parse_add_index_entry (parse, offset, GST_BUFFER_TIMESTAMP (buffer), + !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE); + } + } +#else + if (parse->priv->upstream_seekable && parse->priv->exact_position && GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + gst_base_parse_add_index_entry (parse, offset, GST_BUFFER_TIMESTAMP (buffer), + !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE); + } +#endif /* First buffers are dropped, this means that the subclass needs more * frames to decide on the format and queues them internally */ @@ -1762,6 +1947,18 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, } } +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + if (parse->priv->alp_mp3_mode) { + GST_INFO_OBJECT (parse, "-----------------------------"); + GST_INFO_OBJECT (parse, "[ALP] alp_size_buf_one(%d) alp_size_buf_total(%" G_GUINT64_FORMAT ")",parse->priv->alp_size_buf_one, parse->priv->alp_size_buf_total); + GST_INFO_OBJECT (parse, "[ALP] alp_duration_buf_total(%" GST_TIME_FORMAT ")", GST_TIME_ARGS(parse->priv->alp_duration_buf_total)); + GST_INFO_OBJECT (parse, "[GBUF] size(%d) offset(%" G_GUINT64_FORMAT ")",GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); + GST_INFO_OBJECT (parse, "[GBUF] timestamp(%" GST_TIME_FORMAT ") duration(%" GST_TIME_FORMAT ")", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION (buffer))); + GST_INFO_OBJECT (parse, "-----------------------------"); + } +#endif + return gst_base_parse_push_frame (parse, frame); } @@ -1804,19 +2001,54 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); /* update stats */ - parse->priv->bytecount += GST_BUFFER_SIZE (buffer); - if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) { - parse->priv->framecount++; - if (GST_BUFFER_DURATION_IS_VALID (buffer)) { - parse->priv->acc_duration += GST_BUFFER_DURATION (buffer); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + parse->priv->bytecount += GST_BUFFER_SIZE (buffer); + } else { + parse->priv->bytecount += GST_BUFFER_SIZE (buffer); + if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) { + parse->priv->framecount++; + if (GST_BUFFER_DURATION_IS_VALID (buffer)) { + parse->priv->acc_duration += GST_BUFFER_DURATION (buffer); + } + } + } +#else + parse->priv->bytecount += GST_BUFFER_SIZE (buffer); + if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) { + parse->priv->framecount++; + if (GST_BUFFER_DURATION_IS_VALID (buffer)) { + parse->priv->acc_duration += GST_BUFFER_DURATION (buffer); + } } +#endif + +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + if (parse->priv->alp_mp3_mode) { + GST_INFO_OBJECT (parse, "frame(%"G_GUINT64_FORMAT") bytecount(%"G_GUINT64_FORMAT") acc_duration(%"GST_TIME_FORMAT")", + parse->priv->framecount, parse->priv->bytecount, GST_TIME_ARGS(parse->priv->acc_duration)); } +#endif + /* 0 means disabled */ - if (parse->priv->update_interval < 0) - parse->priv->update_interval = 50; - else if (parse->priv->update_interval > 0 && - ((parse->priv->framecount-1) % parse->priv->update_interval) == 0) - gst_base_parse_update_duration (parse); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + if (parse->priv->update_interval < 0) + parse->priv->update_interval = 50; + else if (parse->priv->update_interval > 0 && parse->priv->framecount > 0) + gst_base_parse_update_duration (parse); + } else { + if (parse->priv->update_interval < 0) + parse->priv->update_interval = 50; + else if (parse->priv->update_interval > 0 && ((parse->priv->framecount-1) % parse->priv->update_interval) == 0) + gst_base_parse_update_duration (parse); + } +#else + if (parse->priv->update_interval < 0) + parse->priv->update_interval = 50; + else if (parse->priv->update_interval > 0 && ((parse->priv->framecount-1) % parse->priv->update_interval) == 0) + gst_base_parse_update_duration (parse); +#endif if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) last_start = last_stop = GST_BUFFER_TIMESTAMP (buffer); @@ -1922,6 +2154,11 @@ gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) * (following newsegment) */ gst_base_parse_update_bitrates (parse, frame); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) + parse->priv->alp_frame_1st = 0; +#endif + if (G_UNLIKELY (parse->priv->pending_events)) { GList *l; @@ -2306,9 +2543,11 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) parse->priv->detect_buffers = NULL; parse->priv->detect_buffers_size = 0; } else { - parse->priv->detect_buffers = - g_list_append (parse->priv->detect_buffers, buffer); - parse->priv->detect_buffers_size += GST_BUFFER_SIZE (buffer); + if(G_LIKELY (buffer)) { + parse->priv->detect_buffers = + g_list_append (parse->priv->detect_buffers, buffer); + parse->priv->detect_buffers_size += GST_BUFFER_SIZE (buffer); + } return GST_FLOW_OK; } } else { @@ -2429,10 +2668,12 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) * fragment coming later, hopefully subclass skips efficiently ... */ timestamp = gst_adapter_prev_timestamp (parse->priv->adapter, NULL); outbuf = gst_adapter_take_buffer (parse->priv->adapter, skip); - outbuf = gst_buffer_make_metadata_writable (outbuf); - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - parse->priv->buffers_pending = - g_slist_prepend (parse->priv->buffers_pending, outbuf); + if(G_LIKELY(outbuf)){ + outbuf = gst_buffer_make_metadata_writable (outbuf); + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + parse->priv->buffers_pending = + g_slist_prepend (parse->priv->buffers_pending, outbuf); + } outbuf = NULL; } else { gst_adapter_flush (parse->priv->adapter, skip); @@ -2481,6 +2722,8 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) /* FIXME: Would it be more efficient to make a subbuffer instead? */ outbuf = gst_adapter_take_buffer (parse->priv->adapter, fsize); + if(G_UNLIKELY(!outbuf)) + goto adapter_underflow; outbuf = gst_buffer_make_metadata_writable (outbuf); /* Subclass may want to know the data offset */ @@ -2511,6 +2754,12 @@ invalid_min: old_min_size, min_size)); return GST_FLOW_ERROR; } +adapter_underflow: + { + GST_ERROR_OBJECT (parse, "Failed to adapter take buffer adapter->size:%d, fsize:%d.", + parse->priv->adapter->size,fsize); + return GST_FLOW_ERROR; + } } /* pull @size bytes at current offset, @@ -2542,9 +2791,15 @@ gst_base_parse_pull_range (GstBaseParse * parse, guint size, } /* refill the cache */ - ret = - gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size, - 64 * 1024), &parse->priv->cache); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) + ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size, 32 * 1024), &parse->priv->cache); + else + ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size, 64 * 1024), &parse->priv->cache); +#else + ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size, 64 * 1024), &parse->priv->cache); +#endif + if (ret != GST_FLOW_OK) { parse->priv->cache = NULL; return ret; @@ -2670,7 +2925,15 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, * maybe it does not need this much, but in the latter case, we know we are * in pull mode here and might as well try to read and supply more anyway * (so does the buffer caching mechanism) */ - fsize = 64 * 1024; +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + fsize = 32 * 1024; + } else { + fsize = 64 * 1024; + } +#else + fsize = 64 * 1024; +#endif while (TRUE) { gboolean res; @@ -2682,6 +2945,7 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, old_min_size = min_size; ret = gst_base_parse_pull_range (parse, min_size, &buffer); + if (ret != GST_FLOW_OK) goto done; @@ -2705,7 +2969,15 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, GST_ERROR_OBJECT (parse, "Failed to detect format but draining"); return GST_FLOW_ERROR; } else { - fsize += 64 * 1024; +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + fsize += 32 * 1024; + } else { + fsize += 64 * 1024; + } +#else + fsize += 64 * 1024; +#endif gst_buffer_unref (buffer); continue; } @@ -2722,6 +2994,7 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, skip = -1; gst_base_parse_frame_update (parse, frame, buffer); res = klass->check_valid_frame (parse, frame, &fsize, &skip); + gst_buffer_replace (&frame->buffer, NULL); if (res) { parse->priv->drain = FALSE; @@ -2748,7 +3021,15 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, parse->priv->discont = TRUE; /* something changed at least; nullify loop check */ if (fsize == G_MAXUINT) - fsize = old_min_size + 64 * 1024; +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + fsize = old_min_size + 32 * 1024; + } else { + fsize = old_min_size + 64 * 1024; + } +#else + fsize = old_min_size + 64 * 1024; +#endif old_min_size = 0; } /* skip == 0 should imply subclass set min_size to need more data; @@ -2783,9 +3064,24 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, } parse->priv->offset += fsize; - frame->buffer = outbuf; +#ifdef GST_BASEPARSE_ALP_EXYNOS_LOG + if (parse->priv->alp_mp3_mode) { + GST_INFO_OBJECT (parse, "-----------------------------"); + GST_INFO_OBJECT (parse, "[ALP] offset(%" G_GUINT64_FORMAT ") += fsize(%d)",parse->priv->offset, fsize); + GST_INFO_OBJECT (parse, "[ALP] alp_mp3_mode(%d) alp_frame_1st(%d)",parse->priv->alp_mp3_mode, parse->priv->alp_frame_1st); + GST_INFO_OBJECT (parse, "[ALP] alp_frame_in_buffer(%d) alp_duration_frame(%" G_GUINT64_FORMAT ")",parse->priv->alp_frame_in_buffer, parse->priv->alp_duration_frame); + GST_INFO_OBJECT (parse, "[ALP] alp_frame_count(%d) alp_duration_frame(%" GST_TIME_FORMAT ")",parse->priv->alp_frame_count, GST_TIME_ARGS(parse->priv->alp_duration_frame)); + GST_INFO_OBJECT (parse, "[ALP] alp_buffer_count(%d) alp_duration_buffer(%" GST_TIME_FORMAT ")",parse->priv->alp_buffer_count, GST_TIME_ARGS(parse->priv->alp_duration_buffer)); + GST_INFO_OBJECT (parse, "[ALP] alp_size_buf_one(%d) alp_size_buf_total(%" G_GUINT64_FORMAT ")",parse->priv->alp_size_buf_one, parse->priv->alp_size_buf_total); + GST_INFO_OBJECT (parse, "[ALP] alp_duration_buf_total(%" GST_TIME_FORMAT ")",GST_TIME_ARGS( parse->priv->alp_duration_buf_total)); + GST_INFO_OBJECT (parse, "-----------------------------"); + GST_INFO_OBJECT (parse, "[OBUF] szie(%d) offset(%" G_GUINT64_FORMAT ")",GST_BUFFER_SIZE (outbuf), GST_BUFFER_OFFSET (outbuf)); + GST_INFO_OBJECT (parse, "-----------------------------"); + } +#endif + done: return ret; @@ -2972,7 +3268,10 @@ gst_base_parse_sink_activate_push (GstPad * pad, gboolean active) parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (parse, "sink activate push %d", active); - +#ifdef GST_EXT_BASEPARSER_MODIFICATION + /* to know early what is the mode */ + parse->priv->expected_pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE; +#endif result = gst_base_parse_activate (parse, active); if (result) @@ -2993,7 +3292,10 @@ gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad)); GST_DEBUG_OBJECT (parse, "activate pull %d", active); - +#ifdef GST_EXT_BASEPARSER_MODIFICATION + /* to know early what is the mode */ + parse->priv->expected_pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE; +#endif result = gst_base_parse_activate (parse, active); if (result) { @@ -3266,8 +3568,18 @@ gst_base_parse_get_duration (GstBaseParse * parse, GstFormat format, res = gst_base_parse_convert (parse, parse->priv->duration_fmt, parse->priv->duration, format, (gint64 *) duration); } else if (format == GST_FORMAT_TIME && parse->priv->estimated_duration != -1) { +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + GST_LOG_OBJECT (parse, "using ALP estimated duration"); + *duration = parse->priv->alp_estimated_duration; + } else { + GST_LOG_OBJECT (parse, "using estimated duration"); + *duration = parse->priv->estimated_duration; + } +#else GST_LOG_OBJECT (parse, "using estimated duration"); *duration = parse->priv->estimated_duration; +#endif res = TRUE; } @@ -3761,12 +4073,27 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) * and the requested segment is maintained exactly, not adjusted any way */ accurate = flags & GST_SEEK_FLAG_ACCURATE; +#ifndef GST_EXT_BASEPARSER_MODIFICATION /* maybe we can be accurate for (almost) free */ gst_base_parse_find_offset (parse, seeksegment.last_stop, TRUE, &start_ts); if (seeksegment.last_stop <= start_ts + TARGET_DIFFERENCE) { GST_DEBUG_OBJECT (parse, "accurate seek possible"); accurate = TRUE; } +#else + if ( parse->priv->accurate_index_seek) { + /* maybe we can be accurate for (almost) free */ + gst_base_parse_find_offset (parse, seeksegment.last_stop, TRUE, &start_ts); + if (seeksegment.last_stop <= start_ts + TARGET_DIFFERENCE) { + GST_DEBUG_OBJECT (parse, "accurate seek possible"); + accurate = TRUE; + } + } else { + GST_DEBUG_OBJECT (parse, "accurate seek FALSE"); + accurate = FALSE; + } +#endif + if (accurate) { GstClockTime startpos = seeksegment.last_stop; @@ -3776,8 +4103,7 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) else startpos -= parse->priv->lead_in_ts; seekpos = gst_base_parse_find_offset (parse, startpos, TRUE, &start_ts); - seekstop = gst_base_parse_find_offset (parse, seeksegment.stop, FALSE, - NULL); + seekstop = gst_base_parse_find_offset (parse, seeksegment.stop, FALSE, NULL); } else { start_ts = seeksegment.last_stop; dstformat = GST_FORMAT_BYTES; @@ -3796,6 +4122,16 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) "seek stop %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT, seeksegment.stop, seekstop); +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 + if (parse->priv->alp_mp3_mode) { + /* seek event on, so update new information */ + parse->priv->alp_seek_on = 1; + parse->priv->alp_size_buf_total = seekpos; + parse->priv->alp_duration_buf_total = start_ts; + GST_INFO_OBJECT (parse, "[SEEK] seek start alp_duration_buf_total (%" GST_TIME_FORMAT ") in alp_size_buf_total: %" G_GINT64_FORMAT, GST_TIME_ARGS(start_ts), seekpos); + } +#endif + if (parse->priv->pad_mode == GST_ACTIVATE_PULL) { gint64 last_stop; @@ -3916,7 +4252,7 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) seek event (in bytes) to upstream. Segment / flush handling happens in corresponding src event handlers */ GST_DEBUG_OBJECT (parse, "seek in PUSH mode"); - if (seekstop >= 0 && seekpos <= seekpos) + if (seekstop >= 0) seekstop = seekpos; new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, seekpos, stop_type, seekstop); @@ -4118,3 +4454,151 @@ gst_base_parse_change_state (GstElement * element, GstStateChange transition) return result; } + +#ifdef GST_EXT_BASEPARSER_MODIFICATION /* get baseparse private param. ex. for amr index table, aac duration */ +void +gst_base_parse_get_upstream_size (GstBaseParse * parse, gint64 * upstream_size) +{ + GST_BASE_PARSE_INDEX_LOCK (parse); + *upstream_size = parse->priv->upstream_size; + GST_INFO_OBJECT (parse, "get upstream_size param for child parser : (%"G_GUINT64_FORMAT")", parse->priv->upstream_size); + GST_BASE_PARSE_INDEX_UNLOCK (parse); +} + +void +gst_base_parse_get_index_last_offset (GstBaseParse * parse, gint64 * index_last_offset) +{ + GST_BASE_PARSE_INDEX_LOCK (parse); + *index_last_offset = parse->priv->index_last_offset; + GST_INFO_OBJECT (parse, "get index_last_offset param for child parser : (%"G_GUINT64_FORMAT")", parse->priv->index_last_offset); + GST_BASE_PARSE_INDEX_UNLOCK (parse); +} + +void +gst_base_parse_get_index_last_ts (GstBaseParse * parse, GstClockTime * index_last_ts) +{ + GST_BASE_PARSE_INDEX_LOCK (parse); + *index_last_ts = parse->priv->index_last_ts; + GST_INFO_OBJECT (parse, "get index_last_ts param for child parser : (%"GST_TIME_FORMAT")", GST_TIME_ARGS(parse->priv->index_last_ts)); + GST_BASE_PARSE_INDEX_UNLOCK (parse); +} + +void +gst_base_parse_get_pad_mode (GstBaseParse * parse, GstActivateMode * pad_mode) +{ + GST_BASE_PARSE_INDEX_LOCK (parse); + *pad_mode = parse->priv->expected_pad_mode; + GST_INFO_OBJECT (parse, "get pad_mode param for child parse: mode num (%d)", parse->priv->expected_pad_mode); + GST_BASE_PARSE_INDEX_UNLOCK (parse); +} + +void +gst_base_parse_set_seek_mode (GstBaseParse * parse, gboolean seek_mode) +{ + g_return_if_fail (parse != NULL); + parse->priv->accurate_index_seek= seek_mode; + if (seek_mode) + GST_INFO_OBJECT (parse, "accurate seek mode ON"); + else + GST_INFO_OBJECT (parse, "accurate seek mode OFF - for large file (over 50MByte)"); +} +#endif + +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 +void +gst_base_parse_get_initial_frame (GstBaseParse * parse, gboolean *initialized) +{ + GST_BASE_PARSE_INDEX_LOCK (parse); + if(parse->priv->framecount == 0) { + *initialized = FALSE; + GST_INFO_OBJECT (parse, "get only initial frame indicator - framecount is always 0 (%d)", parse->priv->framecount); + } else { + *initialized = TRUE; + } + GST_BASE_PARSE_INDEX_UNLOCK (parse); +} + +void +gst_base_parse_set_alp_mode (GstBaseParse * parse, gboolean alp_mde) +{ + g_return_if_fail (parse != NULL); + parse->priv->alp_mp3_mode= alp_mde; + if (alp_mde) { + GST_INFO_OBJECT (parse, "============================="); + GST_INFO_OBJECT (parse, "ALP MP3 SET alp_mp3_mode [%d]", parse->priv->alp_mp3_mode); + GST_INFO_OBJECT (parse, "============================="); + } +} + +void +gst_base_parse_set_1st_frame (GstBaseParse * parse, guint frame_1st, gint bpf) +{ + g_return_if_fail (parse != NULL); + parse->priv->alp_frame_1st = frame_1st; + parse->priv->alp_size_frame_1st = bpf; + GST_INFO_OBJECT (parse, "SET alp_frame_1st flag (%d), bpf_1st (%d)", parse->priv->alp_frame_1st, parse->priv->alp_size_frame_1st); +} + +void +gst_base_parse_set_frame_info (GstBaseParse * parse, guint32 count, gint64 duration, guint32 avgbitrate) +{ + g_return_if_fail (parse != NULL); + parse->priv->alp_frame_in_buffer = count; + parse->priv->alp_duration_frame = duration; + parse->priv->alp_frame_avgbitrate = avgbitrate; + + parse->priv->alp_frame_count += count; + parse->priv->framecount = parse->priv->alp_frame_count; + GST_INFO_OBJECT (parse, "SET alp_frame_count(%d) VS parse->framecount(%d) avgbitrate(%d)", parse->priv->alp_frame_count, parse->priv->framecount, avgbitrate); + GST_INFO_OBJECT (parse, " parse->framecount(%"G_GUINT64_FORMAT") parse->offset(%"G_GUINT64_FORMAT")", parse->priv->framecount, parse->priv->offset); +} + +void +gst_base_parse_set_buffer_info (GstBaseParse * parse, guint32 count, gint64 duration) +{ + g_return_if_fail (parse != NULL); + parse->priv->alp_buffer_count = count; + parse->priv->alp_duration_buffer = duration; + parse->priv->acc_duration += duration; + + if (parse->priv->offset == 0) { + parse->priv->alp_duration_buf_total = 0; //reset for continue next play + } else { + if(parse->priv->alp_seek_on) { + parse->priv->alp_seek_on = 1; // don't need update of timestamp!!!!!! + } else { + parse->priv->alp_duration_buf_total += duration; + } + } + GST_INFO_OBJECT (parse, "SET alp_buffer_count(%d) alp_duration_buf_total(%"GST_TIME_FORMAT") ", parse->priv->alp_buffer_count, GST_TIME_ARGS(parse->priv->alp_duration_buf_total)); +} + +void +gst_base_parse_set_buffer_size (GstBaseParse * parse, guint32 byte_offset) +{ + g_return_if_fail (parse != NULL); + parse->priv->alp_size_buf_one = byte_offset; + if (parse->priv->offset == 0) { + parse->priv->alp_size_buf_total = 0; //reset for continue next play -if I don't used this, then don't operate 'continue play' + } + else { + if(parse->priv->alp_seek_on) { + parse->priv->alp_seek_on = 1; // don't need update of total buffer size !!!!!! --> need next module + } else { + parse->priv->alp_size_buf_total += byte_offset; + } + } + GST_INFO_OBJECT (parse, "SET alp_size_buf_one(%d) alp_size_buf_total(%"G_GUINT64_FORMAT")", parse->priv->alp_size_buf_one, parse->priv->alp_size_buf_total); +} +#endif + +#ifdef GST_EXT_BASEPARSE_ENABLE_WFD +void +gst_base_parse_set_wfd_mode (GstBaseParse * parse, gboolean wfd_mode) +{ + g_return_if_fail (parse != NULL); + parse->priv->wfd_mode = wfd_mode; + if (wfd_mode) + GST_INFO_OBJECT (parse, "WFD mode is enabled"); +} +#endif diff --git a/libs/gst/base/gstbaseparse.h b/libs/gst/base/gstbaseparse.h index fff4d85..ddd0aff 100644 --- a/libs/gst/base/gstbaseparse.h +++ b/libs/gst/base/gstbaseparse.h @@ -34,6 +34,9 @@ G_BEGIN_DECLS #define GST_IS_BASE_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_PARSE)) #define GST_BASE_PARSE_CAST(obj) ((GstBaseParse *)(obj)) +#define GST_BASEPARSE_ALP_EXYNOS_MP3 +//#define GST_BASEPARSE_ALP_EXYNOS_LOG + /** * GST_BASE_PARSE_SRC_PAD: * @obj: base parse instance @@ -324,6 +327,32 @@ gboolean gst_base_parse_add_index_entry (GstBaseParse * parse, gboolean key, gboolean force); +#ifdef GST_EXT_BASEPARSER_MODIFICATION /* get baseparse private param */ +void gst_base_parse_get_upstream_size (GstBaseParse * parse, + gint64 * upstream_size); + +void gst_base_parse_get_index_last_offset (GstBaseParse * parse, + gint64 * index_last_offset); + +void gst_base_parse_get_index_last_ts (GstBaseParse * parse, + GstClockTime * index_last_ts); + +void gst_base_parse_get_pad_mode (GstBaseParse * parse, + GstActivateMode * pad_mode); +void gst_base_parse_set_seek_mode (GstBaseParse * parse, + gboolean seek_mode); +#endif + + +#ifdef GST_BASEPARSE_ALP_EXYNOS_MP3 +void gst_base_parse_get_initial_frame (GstBaseParse * parse, gboolean *initialized); +void gst_base_parse_set_alp_mode (GstBaseParse * parse, gboolean alp_mde); +void gst_base_parse_set_1st_frame (GstBaseParse * parse, guint frame_1st, gint bpf); +void gst_base_parse_set_frame_info (GstBaseParse * parse, guint32 count, gint64 duration, guint32 avgbitrate); +void gst_base_parse_set_buffer_info (GstBaseParse * parse, guint32 count, gint64 duration); +void gst_base_parse_set_buffer_size (GstBaseParse * parse, guint32 byte_offset); +#endif + G_END_DECLS #endif /* __GST_BASE_PARSE_H__ */ diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index a610e2e..082b327 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -154,6 +154,7 @@ #include "gstbasesink.h" #include #include +#include GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug); #define GST_CAT_DEFAULT gst_base_sink_debug @@ -271,8 +272,60 @@ struct _GstBaseSinkPrivate /* for throttling and QoS */ GstClockTime earliest_in_time; GstClockTime throttle_time; + +#ifdef _VSP_SPEED_ + /* parameters using by vsp */ + gboolean vsp_enabled; + gdouble vsp_speed; + /* similar as segment.start */ + gint64 vsp_position; + /* store orignal segment.stop */ + gint64 vsp_stop; + gint64 vsp_last_position; + /* similiar as base_time */ + gint64 vsp_last_rtime; + /* basesink act as parent of videosink */ + gboolean vsp_video; +#endif + + /* clock calibration */ + + gboolean cc_enabled; + struct { + gboolean is_video_sink; + /* if it is prepared to do calibration */ + gboolean do_clock_calibration; + GstClockTime last_expecting_render; + GstClockTime cur_expecting_render; + GstClockTime last_actually_render; + GstClockTime cur_actually_render; + /* the threshold determine whether to do cc */ + GstClockTimeDiff cc_threshold; + /* the adjustment */ + GstClockTimeDiff cc_time; + /* the accumulation of cc */ + GstClockTimeDiff cc_accumulation; + /* cc_stat temporarily */ + guint cc_stats[10]; + }CC; }; +/* Fake clock type to simulate audioclock */ +typedef GstClockTime (*GstFakeFunc) (GstClock *clock, gpointer user_data); +typedef struct { + GstSystemClock clock; + GstFakeFunc fake_func; + gpointer fake_data; +}GstFakeClock; + +typedef struct { + GstFakeFunc old_fake_func; + gpointer old_fake_data; + GstFakeFunc new_fake_func; + gpointer new_fake_data; +}GstFakeData; + + #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size)) /* generic running average, this has a neutral window size */ @@ -313,6 +366,14 @@ enum #define DEFAULT_ENABLE_LAST_BUFFER TRUE #define DEFAULT_THROTTLE_TIME 0 +#ifdef _VSP_SPEED_ +#define DEFAULT_VSP_SPEED 1.0f +#endif + +#define DEFAULT_CC_TIME (10 * GST_MSECOND) +#define DEFAULT_CC_THRESHOLD (1 * GST_MSECOND) +#define DEFAULT_ENABLE_CC TRUE + enum { PROP_0, @@ -327,6 +388,8 @@ enum PROP_BLOCKSIZE, PROP_RENDER_DELAY, PROP_THROTTLE_TIME, + /* enable cc feature or not */ + PROP_ENABLE_CC, PROP_LAST }; @@ -418,6 +481,27 @@ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink, guint8 obj_type, GstMiniObject * obj); +/* CC use */ +static void +basesink_cc_initialize(GstBaseSink *basesink); +static void +basesink_cc_uninitialize(GstBaseSink *basesink); +static void +basesink_cc_is_video_sink(GstBaseSink *basesink, gboolean is_video_sink); +static void +basesink_cc_do_clock_calibration(GstBaseSink *basesink, gboolean do_or_not); +static GstClockTime +basesink_cc_fake_clock_func(GstClock *clock, gpointer user_data); +static void +basesink_cc_wait_jitter_adjust(GstClock *clock, gpointer user_data); +static void +basesink_cc_wait_jitter_revert(GstClock *clock, gpointer user_data); +static GstClockReturn +basesink_cc_wait_calibrated_clock (GstBaseSink *sink, GstClockTime time, GstClockTimeDiff *jitter); +static GstClockReturn +basesink_cc_clock_calibration_wait (GstBaseSink *basesink, GstClockID id, GstClockTimeDiff *jitter); + + static void gst_base_sink_class_init (GstBaseSinkClass * klass) { @@ -555,6 +639,11 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) "The time to keep between rendered buffers (unused)", 0, G_MAXUINT64, DEFAULT_THROTTLE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ENABLE_CC, + g_param_spec_boolean ("enable-cc", "Enable Clock Calibration", + "Enable the cc property", DEFAULT_ENABLE_CC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_base_sink_change_state); gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event); @@ -725,6 +814,18 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class) priv->cached_clock_id = NULL; g_atomic_int_set (&priv->enable_last_buffer, DEFAULT_ENABLE_LAST_BUFFER); priv->throttle_time = DEFAULT_THROTTLE_TIME; + priv->cc_enabled = DEFAULT_ENABLE_CC; + +#ifdef _VSP_SPEED_ + /* vsp default */ + priv->vsp_enabled = FALSE; + priv->vsp_speed = DEFAULT_VSP_SPEED; + priv->vsp_position = 0; + priv->vsp_stop = -1; + priv->vsp_last_position = 0; + priv->vsp_last_rtime = 0; + priv->vsp_video = FALSE; +#endif GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK); } @@ -1366,6 +1467,26 @@ gst_base_sink_get_throttle_time (GstBaseSink * sink) return res; } +gboolean +gst_base_sink_is_cc_enabled(GstBaseSink * sink) +{ + gboolean res; + + g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE); + + res = g_atomic_int_get (&sink->priv->cc_enabled); + return res; +} + +void +gst_base_sink_set_cc_enabled (GstBaseSink * sink, gboolean enabled) +{ + g_return_if_fail (GST_IS_BASE_SINK (sink)); + + g_atomic_int_set (&sink->priv->cc_enabled, enabled); +} + + static void gst_base_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -1406,6 +1527,9 @@ gst_base_sink_set_property (GObject * object, guint prop_id, case PROP_THROTTLE_TIME: gst_base_sink_set_throttle_time (sink, g_value_get_uint64 (value)); break; + case PROP_ENABLE_CC: + gst_base_sink_set_cc_enabled(sink, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1452,6 +1576,9 @@ gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value, case PROP_THROTTLE_TIME: g_value_set_uint64 (value, gst_base_sink_get_throttle_time (sink)); break; + case PROP_ENABLE_CC: + g_value_set_boolean(value, gst_base_sink_is_cc_enabled (sink)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1530,6 +1657,25 @@ gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad, * We protect with the OBJECT_LOCK so that we can use the values to * safely answer a POSITION query. */ GST_OBJECT_LOCK (basesink); + +#ifdef _VSP_SPEED_ + /* update segment according to video/audio */ + if(basesink->priv->vsp_enabled) { + + if(basesink->priv->vsp_video) { + + rate = basesink->priv->vsp_speed; + + } else { + + basesink->priv->vsp_stop = stop; + if(stop != -1) { + stop = start + (stop - start) / basesink->priv->vsp_speed; + } + } + } +#endif + gst_segment_set_newsegment_full (segment, update, rate, arate, format, start, stop, time); @@ -2144,6 +2290,179 @@ gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time) return time; } +static void +basesink_cc_initialize(GstBaseSink *basesink) +{ + GstBaseSinkPrivate *priv; + + GST_OBJECT_LOCK(basesink); + +#define SYSCLK_RESET(priv); \ + priv = basesink->priv; \ + priv->CC.is_video_sink = FALSE; \ + priv->CC.do_clock_calibration = FALSE; \ + priv->CC.last_expecting_render = 0; \ + priv->CC.cur_expecting_render = 0; \ + priv->CC.last_actually_render = 0; \ + priv->CC.cur_actually_render = 0; \ + priv->CC.cc_threshold = DEFAULT_CC_THRESHOLD; \ + priv->CC.cc_time = DEFAULT_CC_TIME; \ + priv->CC.cc_accumulation = 0; \ + for(int i = 0; i < 10; ++i) priv->CC.cc_stats[i] = 0; \ + priv->start = GST_CLOCK_TIME_NONE; + + SYSCLK_RESET(priv); + + GST_OBJECT_UNLOCK(basesink); +} + +static void +basesink_cc_uninitialize(GstBaseSink *basesink) +{ + GstBaseSinkPrivate *priv; + GST_OBJECT_LOCK(basesink); + + SYSCLK_RESET(priv); + + GST_OBJECT_UNLOCK(basesink); +} + +static void +basesink_cc_is_video_sink(GstBaseSink *basesink, gboolean is_video_sink) +{ + GST_OBJECT_LOCK(basesink); + basesink->priv->CC.is_video_sink = is_video_sink; + GST_OBJECT_UNLOCK(basesink); +} + +static void +basesink_cc_do_clock_calibration(GstBaseSink *basesink, gboolean do_or_not) +{ + GST_OBJECT_LOCK(basesink); + basesink->priv->CC.do_clock_calibration = do_or_not; + GST_OBJECT_UNLOCK(basesink); +} + +static GstClockTime +basesink_cc_fake_clock_func(GstClock *clock, gpointer user_data) +{ + GstClockTime result, a_result, s_result; + GstFakeData *p_fake_data; + GstBaseSink *basesink; + GstBaseSinkPrivate *priv; + GstClockTime expecting_actually_render; + GstClockTimeDiff jitter, expecting_jitter; + + p_fake_data = (GstFakeData *)user_data; + basesink = (GstBaseSink *)p_fake_data->new_fake_data; + priv = basesink->priv; + + a_result = p_fake_data->old_fake_func(clock,p_fake_data->old_fake_data); + + /* check if need do CC */ + if(!priv->CC.do_clock_calibration) { + result = a_result; + goto done; + } + + expecting_actually_render = priv->CC.last_actually_render + + priv->CC.cur_expecting_render - priv->CC.last_expecting_render; + s_result = gst_util_get_timestamp(); + + /* we hope to wait the value of expecting_jitter */ + expecting_jitter = expecting_actually_render - s_result; + /* while if a_result , we will wait the value of jitter */ + jitter = priv->CC.cur_expecting_render - a_result; + + if(expecting_actually_render <= s_result) { + result = priv->CC.cur_expecting_render; + GST_LOG("we are late , render ASAP"); + goto done; + } + + /* audioclock flushes , handle this to avoid discard frame */ + /* + if(jitter < 0) { + result = priv->CC.cur_expecting_render - priv->CC.cc_time; + GST_LOG("audio clock flush"); + goto done; + } + */ + + /* do real clock calibration using cc_time */ + if(jitter - expecting_jitter < priv->CC.cc_time + && jitter - expecting_jitter > - priv->CC.cc_time) { + + /* adjust jitter to expecting_jitter */ + result = priv->CC.cur_expecting_render - expecting_jitter; + } else if(jitter - expecting_jitter > priv->CC.cc_time) { + + result = a_result + priv->CC.cc_time; + } else + result = a_result - priv->CC.cc_time; + + GST_LOG("jitter=%"GST_TIME_FORMAT",expecting_jitter=%"GST_TIME_FORMAT",new jitter=%"GST_TIME_FORMAT, + GST_TIME_ARGS(jitter), + GST_TIME_ARGS(expecting_jitter), + GST_TIME_ARGS(priv->CC.cur_expecting_render - result)); +done: + priv->CC.cc_accumulation += (result - a_result); + return result; +} + +static void +basesink_cc_wait_jitter_adjust(GstClock *clock, gpointer user_data) +{ + GstFakeClock *p_fake_clock; + GstFakeData *p_fake_data; + p_fake_clock = (GstFakeClock *)clock; + p_fake_data = (GstFakeData *)user_data; + p_fake_clock->fake_func = p_fake_data->new_fake_func; + p_fake_clock->fake_data = p_fake_data; +} + +static void +basesink_cc_wait_jitter_revert(GstClock *clock, gpointer user_data) +{ + GstFakeClock *p_fake_clock; + GstFakeData *p_fake_data; + p_fake_clock = (GstFakeClock *)clock; + p_fake_data = (GstFakeData *)user_data; + p_fake_clock->fake_func = p_fake_data->old_fake_func; + p_fake_clock->fake_data = p_fake_data->old_fake_data; + + /* revert to default */ + gst_system_clock_wait_adjust(clock, NULL, NULL); + gst_system_clock_wait_revert(clock, NULL, NULL); +} + + +static GstClockReturn +basesink_cc_clock_calibration_wait (GstBaseSink *basesink, GstClockID id, GstClockTimeDiff *jitter) +{ + GstClock *clock; + /* local visible , global effective */ + static GstFakeData fake_data = {0,}; + GstFakeClock *p_fake_clock; + GstClockReturn result; + + g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); + + clock = GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) id); + + p_fake_clock = (GstFakeClock *)clock; + + fake_data.old_fake_func = p_fake_clock->fake_func; + fake_data.old_fake_data = p_fake_clock->fake_data; + fake_data.new_fake_func = basesink_cc_fake_clock_func; + fake_data.new_fake_data = basesink; + + gst_system_clock_wait_adjust(clock, basesink_cc_wait_jitter_adjust, &fake_data); + gst_system_clock_wait_revert(clock, basesink_cc_wait_jitter_revert, &fake_data); + + return gst_clock_id_wait(id, jitter); +} + /** * gst_base_sink_wait_clock: * @sink: the sink @@ -2174,79 +2493,146 @@ GstClockReturn gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, GstClockTimeDiff * jitter) { - GstClockReturn ret; - GstClock *clock; - GstClockTime base_time; - - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) - goto invalid_time; - - GST_OBJECT_LOCK (sink); - if (G_UNLIKELY (!sink->sync)) - goto no_sync; - - if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL)) - goto no_clock; - - base_time = GST_ELEMENT_CAST (sink)->base_time; - GST_LOG_OBJECT (sink, - "time %" GST_TIME_FORMAT ", base_time %" GST_TIME_FORMAT, - GST_TIME_ARGS (time), GST_TIME_ARGS (base_time)); - - /* add base_time to running_time to get the time against the clock */ - time += base_time; - - /* Re-use existing clockid if available */ - /* FIXME: Casting to GstClockEntry only works because the types - * are the same */ - if (G_LIKELY (sink->priv->cached_clock_id != NULL - && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv-> - cached_clock_id) == clock)) { - if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, - time)) { - gst_clock_id_unref (sink->priv->cached_clock_id); - sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); - } - } else { - if (sink->priv->cached_clock_id != NULL) - gst_clock_id_unref (sink->priv->cached_clock_id); - sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); - } - GST_OBJECT_UNLOCK (sink); - - /* A blocking wait is performed on the clock. We save the ClockID - * so we can unlock the entry at any time. While we are blocking, we - * release the PREROLL_LOCK so that other threads can interrupt the - * entry. */ - sink->clock_id = sink->priv->cached_clock_id; - /* release the preroll lock while waiting */ +#define GST_BASE_SINK_WAIT_CLOCK_BEGIN \ + GstClockReturn ret; \ + GstClock *clock; \ + GstClockTime base_time; \ + \ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) \ + goto invalid_time; \ + \ + GST_OBJECT_LOCK (sink); \ + if (G_UNLIKELY (!sink->sync)) \ + goto no_sync; \ + \ + if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL)) \ + goto no_clock; \ + \ + base_time = GST_ELEMENT_CAST (sink)->base_time; \ + GST_LOG_OBJECT (sink, \ + "time %" GST_TIME_FORMAT ", base_time %" GST_TIME_FORMAT, \ + GST_TIME_ARGS (time), GST_TIME_ARGS (base_time)); \ + \ + /* add base_time to running_time to get the time against the clock */ \ + time += base_time; \ + \ + /* Re-use existing clockid if available */ \ + /* FIXME: Casting to GstClockEntry only works because the types \ + * are the same */ \ + if (G_LIKELY (sink->priv->cached_clock_id != NULL \ + && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv-> \ + cached_clock_id) == clock)) { \ + if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, \ + time)) { \ + gst_clock_id_unref (sink->priv->cached_clock_id); \ + sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); \ + } \ + } else { \ + if (sink->priv->cached_clock_id != NULL) \ + gst_clock_id_unref (sink->priv->cached_clock_id); \ + sink->priv->cached_clock_id = gst_clock_new_single_shot_id (clock, time); \ + } \ + GST_OBJECT_UNLOCK (sink); \ + \ + /* A blocking wait is performed on the clock. We save the ClockID \ + * so we can unlock the entry at any time. While we are blocking, we \ + * release the PREROLL_LOCK so that other threads can interrupt the \ + * entry. */ \ + sink->clock_id = sink->priv->cached_clock_id; \ + /* release the preroll lock while waiting */ \ GST_PAD_PREROLL_UNLOCK (sink->sinkpad); + GST_BASE_SINK_WAIT_CLOCK_BEGIN ret = gst_clock_id_wait (sink->priv->cached_clock_id, jitter); - GST_PAD_PREROLL_LOCK (sink->sinkpad); - sink->clock_id = NULL; - - return ret; +#define GST_BASE_SINK_WAIT_CLOCK_END \ + GST_PAD_PREROLL_LOCK (sink->sinkpad); \ + sink->clock_id = NULL; \ + \ + return ret; \ + \ + /* no syncing needed */ \ +invalid_time: \ + { \ + GST_DEBUG_OBJECT (sink, "time not valid, no sync needed"); \ + return GST_CLOCK_BADTIME; \ + } \ +no_sync: \ + { \ + GST_DEBUG_OBJECT (sink, "sync disabled"); \ + GST_OBJECT_UNLOCK (sink); \ + return GST_CLOCK_BADTIME; \ + } \ +no_clock: \ + { \ + GST_DEBUG_OBJECT (sink, "no clock, can't sync"); \ + GST_OBJECT_UNLOCK (sink); \ + return GST_CLOCK_BADTIME; \ + } + + GST_BASE_SINK_WAIT_CLOCK_END +} - /* no syncing needed */ -invalid_time: - { - GST_DEBUG_OBJECT (sink, "time not valid, no sync needed"); - return GST_CLOCK_BADTIME; - } -no_sync: - { - GST_DEBUG_OBJECT (sink, "sync disabled"); - GST_OBJECT_UNLOCK (sink); - return GST_CLOCK_BADTIME; - } -no_clock: - { - GST_DEBUG_OBJECT (sink, "no clock, can't sync"); - GST_OBJECT_UNLOCK (sink); - return GST_CLOCK_BADTIME; - } +GstClockReturn +basesink_cc_wait_calibrated_clock (GstBaseSink *sink, GstClockTime time, + GstClockTimeDiff *jitter) +{ +/* instance must be subclass of type . return TRUE on success +no depends on GST_BASE_LIBS (no call GST_IS_AUDIO_CLOCK(clock)) */ +#define _G_TYPE_MUST_BE_SUB(instance, type) ({ \ + GTypeInstance *__inst;__inst = (GTypeInstance*) instance; \ + GType __t;__t = type; \ + gboolean __r; \ + if(!__inst || !__inst->g_class) \ + __r = FALSE; \ + else if( (__inst->g_class->g_type != __t) \ + && g_type_check_instance_is_a (__inst, __t)) \ + __r = TRUE; \ + else \ + __r = FALSE; \ + __r; \ + }) + + GstClockTimeDiff expecting_interval, actually_interval; + + GST_BASE_SINK_WAIT_CLOCK_BEGIN + + if(sink->priv->CC.is_video_sink + && _G_TYPE_MUST_BE_SUB(clock, GST_TYPE_SYSTEM_CLOCK)) { + + GST_OBJECT_LOCK(sink); + sink->priv->CC.cur_expecting_render = time; + sink->priv->CC.last_actually_render = sink->priv->CC.cur_actually_render; + GST_OBJECT_UNLOCK(sink); + + expecting_interval = sink->priv->CC.cur_expecting_render + - sink->priv->CC.last_expecting_render; + + ret = basesink_cc_clock_calibration_wait(sink, sink->priv->cached_clock_id, jitter); + + GST_OBJECT_LOCK(sink); + sink->priv->CC.last_expecting_render = time; + sink->priv->CC.cur_actually_render = gst_util_get_timestamp(); + GST_OBJECT_UNLOCK(sink); + + actually_interval = sink->priv->CC.cur_actually_render + - sink->priv->CC.last_actually_render; + + /* cosume speed smaller than cc_threshold , consider it is proper timing to do cc */ + if(!sink->priv->CC.do_clock_calibration) { + if(actually_interval - expecting_interval < sink->priv->CC.cc_threshold + && actually_interval - expecting_interval > -sink->priv->CC.cc_threshold) + { + GST_WARNING("Timing to do CC"); + basesink_cc_do_clock_calibration(sink, TRUE); + } + } + + } + else + ret = gst_clock_id_wait (sink->priv->cached_clock_id, jitter); + + GST_BASE_SINK_WAIT_CLOCK_END } /** @@ -2569,7 +2955,11 @@ again: /* This function will return immediately if start == -1, no clock * or sync is disabled with GST_CLOCK_BADTIME. */ - status = gst_base_sink_wait_clock (basesink, stime, &jitter); + + if(priv->cc_enabled) + status = basesink_cc_wait_calibrated_clock(basesink, stime, &jitter); + else + status = gst_base_sink_wait_clock (basesink, stime, &jitter); GST_DEBUG_OBJECT (basesink, "clock returned %d, jitter %c%" GST_TIME_FORMAT, status, (jitter < 0 ? '-' : ' '), GST_TIME_ARGS (ABS (jitter))); @@ -2922,7 +3312,19 @@ gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start) priv = basesink->priv; if (start) { - priv->start = gst_util_get_timestamp (); + + GstClockTime now = gst_util_get_timestamp (); + + if(priv->CC.is_video_sink && GST_CLOCK_TIME_IS_VALID(priv->start)) { + + int index = (GST_TIME_AS_MSECONDS(now - priv->start) % GST_MSECOND) / 10; + if(index >= 0 && index < 10) { + priv->CC.cc_stats[index]++; + GST_LOG("index(%d) , count(%d)", index, priv->CC.cc_stats[index]); + } + } + + priv->start = now; } else { GstClockTime elapsed; @@ -3525,6 +3927,66 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); break; +#ifdef _VSP_SPEED_ + case GST_EVENT_CUSTOM_DOWNSTREAM: + { + GValue * value; + GstStructure *structure = event->structure; + if(gst_structure_has_name(structure,"vsp/enable")) { + value = gst_structure_get_value(structure,"enable"); + gboolean enabled = g_value_get_boolean (value); + + GST_OBJECT_LOCK(basesink); + basesink->priv->vsp_enabled = enabled; + GST_OBJECT_UNLOCK(basesink); + + GST_DEBUG("vsp/enable:enabled=%d",enabled); + + gst_event_unref (event); + + break; + } else if(gst_structure_has_name(structure,"vsp/speed")) { + GstClock *clock = GST_ELEMENT_CLOCK (basesink); + value = gst_structure_get_value(structure,"speed"); + gdouble speed = g_value_get_double (value); + value = gst_structure_get_value(structure,"position"); + gint64 position = g_value_get_int64 (value); + + GST_DEBUG("vsp/speed:speed=%2f,position=%lld",speed,position); + + GST_OBJECT_LOCK(basesink); + + /* update segment.stop as streaming time has been changed by audiovsp */ + /* formula: stop1 = rtime0 + (stop - stime1) / speed1 + * stop2 = rtime0 + (stime2 - stime2) / speed1 + (stop - stime2) / speed2 + * ...... + */ + +#define UPDATE_SEGMENT(stop) \ + if(GST_CLOCK_TIME_IS_VALID(stop)) { \ + if(!GST_CLOCK_TIME_IS_VALID(basesink->priv->vsp_stop)) { \ + basesink->priv->vsp_stop = stop; \ + } \ + stop = stop \ + + (basesink->priv->vsp_stop - position) \ + * (1/speed - 1/basesink->priv->vsp_speed); \ + } + + UPDATE_SEGMENT(basesink->abidata.ABI.clip_segment->stop); + UPDATE_SEGMENT(basesink->segment.stop); + + basesink->priv->vsp_speed = speed; + basesink->priv->vsp_position = position; + basesink->priv->vsp_last_rtime = clock ? gst_clock_get_time(clock) : 0; + + GST_OBJECT_UNLOCK(basesink); + + gst_event_unref (event); + break; + } + /* no break here,let it go down */ + } +#endif default: /* other events are sent to queue or subclass depending on if they * are serialized. */ @@ -3652,14 +4114,24 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, /* check if the buffer needs to be dropped, we first ask the subclass for the * start and end */ - if (bclass->get_times) + if (bclass->get_times) { bclass->get_times (basesink, time_buf, &start, &end); + } if (!GST_CLOCK_TIME_IS_VALID (start)) { /* if the subclass does not want sync, we use our own values so that we at * least clip the buffer to the segment */ gst_base_sink_get_times (basesink, time_buf, &start, &end); } +#ifdef _VSP_SPEED_ + else { + basesink->priv->vsp_video = TRUE; + basesink_cc_is_video_sink(basesink,TRUE); + } +#else + else + basesink_cc_is_video_sink(basesink,TRUE); +#endif GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); @@ -4466,6 +4938,68 @@ activate_failed: } } +#ifdef _VSP_SPEED_ +static gboolean +gst_base_sink_perform_custom_upstream(GstBaseSink *basesink, GstPad *pad, GstEvent *event) +{ + GValue * value; + GstStructure *structure = event->structure; + gboolean result = FALSE; + + /* only handle in video case */ + if(basesink->priv->vsp_video + && gst_structure_has_name(structure,"application/speed")) { + value = gst_structure_get_value(structure,"enable"); + basesink->priv->vsp_enabled = g_value_get_boolean (value); + + result = TRUE; + } + return result; +} + +static gboolean +gst_base_sink_perform_speed(GstBaseSink *basesink, GstPad *pad, GstEvent **event) +{ + gboolean result = FALSE; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; + + gst_event_parse_seek (*event, &rate, &format, &flags, &start_type, &start, + &stop_type, &stop); + /* only handle in video case */ + if(basesink->priv->vsp_video + && basesink->priv->vsp_enabled) { + + if(basesink->priv->vsp_speed != rate) { + + if(format != GST_FORMAT_TIME) { + result = FALSE; + goto done; + } + + /* need to update segment.start && segment.rate */ + basesink->priv->vsp_speed = rate; + gst_base_sink_event(pad, + gst_event_new_new_segment (TRUE, rate, format, + start, stop, start)); + result = TRUE; + } else { + /* forward seek with rate = 1.0 */ + gst_event_unref(*event); + + *event = gst_event_new_seek(1.0, + format,flags,start_type,start,stop_type,stop); + } + } + +done: + return result; +} +#endif + /* send an event to our sinkpad peer. */ static gboolean gst_base_sink_send_event (GstElement * element, GstEvent * event) @@ -4513,11 +5047,24 @@ gst_base_sink_send_event (GstElement * element, GstEvent * event) /* in pull mode we will execute the seek */ if (mode == GST_ACTIVATE_PULL) result = gst_base_sink_perform_seek (basesink, pad, event); +#ifdef _VSP_SPEED_ + else { + result = gst_base_sink_perform_speed (basesink, pad, &event); + if(result) + forward = FALSE; + } +#endif break; case GST_EVENT_STEP: result = gst_base_sink_perform_step (basesink, pad, event); forward = FALSE; break; +#ifdef _VSP_SPEED_ + case GST_EVENT_CUSTOM_UPSTREAM: + result = gst_base_sink_perform_custom_upstream (basesink, pad, event); + if(result) + forward = FALSE; +#endif default: break; } @@ -4679,6 +5226,13 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, GST_DEBUG_OBJECT (basesink, "using last seen timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (last)); *cur = last; + +#ifdef _VSP_SPEED_ + GST_OBJECT_LOCK(basesink); + if(basesink->priv->vsp_enabled && !basesink->priv->vsp_video) + *cur = basesink->priv->vsp_last_position; + GST_OBJECT_UNLOCK(basesink); +#endif } else { if (oformat != tformat) { /* convert accum, time and duration to time */ @@ -4712,6 +5266,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, * rate and applied rate. */ base += accum; base += latency; + if (GST_CLOCK_DIFF (base, now) < 0) base = now; @@ -4720,8 +5275,29 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, if (rate < 0.0) time += duration; +#ifdef _VSP_SPEED_ + GST_OBJECT_LOCK(basesink); + if(basesink->priv->vsp_enabled && !basesink->priv->vsp_video) { + + /* always assign vsp_last_rtime a valid value */ + if(basesink->priv->vsp_last_rtime <= 0) + basesink->priv->vsp_last_rtime = base; + + *cur = basesink->priv->vsp_position + + gst_guint64_to_gdouble (now - basesink->priv->vsp_last_rtime) + * basesink->priv->vsp_speed; + basesink->priv->vsp_last_position = *cur; + /* did trust segment when vsp enabled as set-speed op did not send newsegment now */ + last = -1; + } + else +#endif *cur = time + gst_guint64_to_gdouble (now - base) * rate; +#ifdef _VSP_SPEED_ + GST_OBJECT_UNLOCK(basesink); +#endif + if (in_paused) { /* never report less than segment values in paused */ if (last != -1) @@ -4729,7 +5305,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, } else { /* never report more than last seen position in playing */ if (last != -1) - *cur = MIN (last, *cur); + *cur = MIN (last, *cur); } GST_DEBUG_OBJECT (basesink, @@ -5033,6 +5609,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) priv->have_latency = TRUE; } GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + + /* initialize cc structure */ + basesink_cc_initialize(basesink); + break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: GST_PAD_PREROLL_LOCK (basesink->sinkpad); @@ -5087,6 +5667,11 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) * And it should be unmarked, since e.g. losing our position upon flush * does not really change state to PAUSED ... */ g_atomic_int_set (&basesink->priv->to_playing, FALSE); +#ifdef _VSP_SPEED_ + if(GST_IS_SYSTEM_CLOCK(GST_ELEMENT_CLOCK(basesink))) { + priv->vsp_last_rtime = gst_clock_get_time(GST_ELEMENT_CLOCK(basesink)); + } +#endif break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: g_atomic_int_set (&basesink->priv->to_playing, FALSE); @@ -5179,6 +5764,9 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll"); } GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + + /* unitialize cc structure */ + basesink_cc_uninitialize(basesink); break; case GST_STATE_CHANGE_READY_TO_NULL: if (bclass->stop) { diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 70f41a3..0f352d4 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -202,10 +202,6 @@ enum #define DEFAULT_TYPEFIND FALSE #define DEFAULT_DO_TIMESTAMP FALSE -#ifdef GST_EXT_MODIFIED_DQBUF -#define DEFAULT_YIELD_TIME 200 -#endif /* GST_EXT_MODIFIED_DQBUF */ - enum { PROP_0, @@ -2417,13 +2413,6 @@ gst_base_src_loop (GstPad * pad) src = GST_BASE_SRC (GST_OBJECT_PARENT (pad)); -#ifdef GST_EXT_MODIFIED_DQBUF - if ((src->live_running) && (!src->blive_play)) { - sched_yield(); - usleep(DEFAULT_YIELD_TIME); - } -#endif /* GST_EXT_MODIFIED_DQBUF */ - GST_LIVE_LOCK (src); if (G_UNLIKELY (src->priv->flushing)) @@ -2951,10 +2940,6 @@ gst_base_src_set_playing (GstBaseSrc * basesrc, gboolean live_play) bclass->unlock (basesrc); } -#ifdef GST_EXT_MODIFIED_DQBUF - basesrc->blive_play = live_play; -#endif /* GST_EXT_MODIFIED_DQBUF */ - /* we are now able to grab the LIVE lock, when we get it, we can be * waiting for PLAYING while blocked in the LIVE cond or we can be waiting * for the clock. */ diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index 80aca8d..ba8544c 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -78,9 +78,6 @@ struct _GstBaseSrc { GCond *live_cond; gboolean is_live; gboolean live_running; -#ifdef GST_EXT_MODIFIED_DQBUF - gboolean blive_play; -#endif /* GST_EXT_MODIFIED_DQBUF */ /* MT-protected (with LOCK) */ gint blocksize; /* size of buffers when operating push based */ diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c index 7fb0bf4..f42cc0c 100644 --- a/libs/gst/base/gstcollectpads.c +++ b/libs/gst/base/gstcollectpads.c @@ -130,6 +130,11 @@ gst_collect_pads_init (GstCollectPads * pads, GstCollectPadsClass * g_class) pads->eospads = 0; pads->started = FALSE; +#ifdef WFD_MODE + pads->wfd_mode = FALSE; + pads->first_collect = TRUE; +#endif + /* members to manage the pad list */ pads->abidata.ABI.pad_lock = g_mutex_new (); pads->abidata.ABI.pad_cookie = 0; @@ -1137,6 +1142,45 @@ gst_collect_pads_check_collected (GstCollectPads * pads) * we can get a busy loop here if the element does not pop from the collect * function */ +#ifdef WFD_MODE + if (pads->wfd_mode) { + /* Call plugin's callback for any stream in turn. + CAUTION : This is specific for mpegtsmux for wifi display */ + if (pads->first_collect) { + GST_WARNING("This is first collect..."); + if (pads->queuedpads + pads->eospads >= pads->numpads) { + GST_WARNING("This is first to collect all streams...calling %s", GST_DEBUG_FUNCPTR_NAME (pads->func)); + flow_ret = pads->func (pads, pads->user_data); + + pads->first_collect = FALSE; + } + } else { + if (pads->queuedpads > 0) { + GST_DEBUG ("One of all active pads (%d, %d, %d) have data, calling %s", + pads->queuedpads, pads->eospads, pads->numpads, GST_DEBUG_FUNCPTR_NAME (pads->func)); + flow_ret = pads->func (pads, pads->user_data); + } + } + } else { + while (((pads->queuedpads + pads->eospads) >= pads->numpads)) { + GST_DEBUG ("All active pads (%d + %d >= %d) have data, calling %s", + pads->queuedpads, pads->eospads, pads->numpads, + GST_DEBUG_FUNCPTR_NAME (pads->func)); + flow_ret = pads->func (pads, pads->user_data); + collected = TRUE; + + /* break on error */ + if (flow_ret != GST_FLOW_OK) + break; + /* Don't keep looping after telling the element EOS or flushing */ + if (pads->queuedpads == 0) + break; + } + if (!collected) + GST_DEBUG ("Not all active pads (%d) have data, continuing", + pads->numpads); + } +#else while (((pads->queuedpads + pads->eospads) >= pads->numpads)) { GST_DEBUG ("All active pads (%d + %d >= %d) have data, calling %s", pads->queuedpads, pads->eospads, pads->numpads, @@ -1154,6 +1198,7 @@ gst_collect_pads_check_collected (GstCollectPads * pads) if (!collected) GST_DEBUG ("Not all active pads (%d) have data, continuing", pads->numpads); +#endif } return flow_ret; } @@ -1468,3 +1513,17 @@ error: goto unlock_done; } } + +#ifdef WFD_MODE +void +gst_collect_pads_set_wfd_mode(GstCollectPads * pads, gboolean mode) +{ + g_return_if_fail (pads != NULL); + g_return_if_fail (GST_IS_COLLECT_PADS (pads)); + + GST_OBJECT_LOCK (pads); + pads->wfd_mode = mode; + GST_OBJECT_UNLOCK (pads); +} +#endif + diff --git a/libs/gst/base/gstcollectpads.h b/libs/gst/base/gstcollectpads.h index 939c2f6..d5ef655 100644 --- a/libs/gst/base/gstcollectpads.h +++ b/libs/gst/base/gstcollectpads.h @@ -33,6 +33,8 @@ G_BEGIN_DECLS #define GST_IS_COLLECT_PADS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECT_PADS)) #define GST_IS_COLLECT_PADS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECT_PADS)) +#define WFD_MODE + typedef struct _GstCollectData GstCollectData; typedef struct _GstCollectPads GstCollectPads; typedef struct _GstCollectPadsPrivate GstCollectPadsPrivate; @@ -155,6 +157,11 @@ struct _GstCollectPads { /* with LOCK and PAD_LOCK*/ gboolean started; +#ifdef WFD_MODE + /* mode for wifi display : If wfd is true, pads collection is working differently */ + gboolean wfd_mode; + gboolean first_collect; +#endif /*< private >*/ union { struct { @@ -218,6 +225,10 @@ GstBuffer * gst_collect_pads_take_buffer (GstCollectPads * pads, GstColle guint gst_collect_pads_flush (GstCollectPads *pads, GstCollectData *data, guint size); +#ifdef WFD_MODE +void gst_collect_pads_set_wfd_mode (GstCollectPads * pads, gboolean mode); +#endif + G_END_DECLS #endif /* __GST_COLLECT_PADS_H__ */ diff --git a/libs/gst/base/gstdataqueue.c b/libs/gst/base/gstdataqueue.c index 2d325e3..052dc93 100644 --- a/libs/gst/base/gstdataqueue.c +++ b/libs/gst/base/gstdataqueue.c @@ -465,6 +465,21 @@ flushing: } } +#ifdef GST_EXT_DATA_QUEUE_MODIFICATION +static gboolean +_gst_data_queue_wait_non_empty (GstDataQueue * queue) +{ + while (gst_data_queue_locked_is_empty (queue)) { + queue->abidata.ABI.waiting_add = TRUE; + g_cond_wait (queue->item_add, queue->qlock); + queue->abidata.ABI.waiting_add = FALSE; + if (queue->flushing) + return FALSE; + } + return TRUE; +} +#endif + /** * gst_data_queue_pop: * @queue: a #GstDataQueue. @@ -497,6 +512,10 @@ gst_data_queue_pop (GstDataQueue * queue, GstDataQueueItem ** item) g_signal_emit (queue, gst_data_queue_signals[SIGNAL_EMPTY], 0); GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing); +#ifdef GST_EXT_DATA_QUEUE_MODIFICATION + if (!_gst_data_queue_wait_non_empty (queue)) + goto flushing; +#else while (gst_data_queue_locked_is_empty (queue)) { queue->abidata.ABI.waiting_add = TRUE; g_cond_wait (queue->item_add, queue->qlock); @@ -504,6 +523,7 @@ gst_data_queue_pop (GstDataQueue * queue, GstDataQueueItem ** item) if (queue->flushing) goto flushing; } +#endif } /* Get the item from the GQueue */ @@ -532,6 +552,61 @@ flushing: } } +#ifdef GST_EXT_DATA_QUEUE_MODIFICATION +/** + * gst_data_queue_peek: + * @queue: a #GstDataQueue. + * @item: pointer to store the returned #GstDataQueueItem. + * + * Retrieves the first @item available on the @queue without removing it. + * If the queue is currently empty, the call will block until at least + * one item is available, OR the @queue is set to the flushing state. + * MT safe. + * + * Returns: #TRUE if an @item was successfully retrieved from the @queue. + * + * Since: 1.2.0 + */ +gboolean +gst_data_queue_peek (GstDataQueue * queue, GstDataQueueItem ** item) +{ + g_return_val_if_fail (GST_IS_DATA_QUEUE (queue), FALSE); + g_return_val_if_fail (item != NULL, FALSE); + + GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing); + + STATUS (queue, "before peeking"); + + if (gst_data_queue_locked_is_empty (queue)) { + GST_DATA_QUEUE_MUTEX_UNLOCK (queue); + if (G_LIKELY (queue->emptycallback)) + queue->emptycallback (queue, queue->checkdata); + else + g_signal_emit (queue, gst_data_queue_signals[SIGNAL_EMPTY], 0); + GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing); + + if (!_gst_data_queue_wait_non_empty (queue)) + goto flushing; + } + + /* Get the item from the GQueue */ + *item = g_queue_peek_head (queue->queue); + + STATUS (queue, "after peeking"); + GST_DATA_QUEUE_MUTEX_UNLOCK (queue); + + return TRUE; + + /* ERRORS */ +flushing: + { + GST_DEBUG ("queue:%p, we are flushing", queue); + GST_DATA_QUEUE_MUTEX_UNLOCK (queue); + return FALSE; + } +} +#endif + /** * gst_data_queue_drop_head: * @queue: The #GstDataQueue to drop an item from. diff --git a/libs/gst/base/gstdataqueue.h b/libs/gst/base/gstdataqueue.h index dea1954..2614c0e 100644 --- a/libs/gst/base/gstdataqueue.h +++ b/libs/gst/base/gstdataqueue.h @@ -167,6 +167,9 @@ GstDataQueue * gst_data_queue_new_full (GstDataQueueCheckFullFunction chec gboolean gst_data_queue_push (GstDataQueue * queue, GstDataQueueItem * item); gboolean gst_data_queue_pop (GstDataQueue * queue, GstDataQueueItem ** item); +#ifdef GST_EXT_DATA_QUEUE_MODIFICATION +gboolean gst_data_queue_peek (GstDataQueue * queue, GstDataQueueItem ** item); +#endif void gst_data_queue_flush (GstDataQueue * queue); void gst_data_queue_set_flushing (GstDataQueue * queue, gboolean flushing); diff --git a/libs/gst/helpers/Makefile.am b/libs/gst/helpers/Makefile.am index ca46fd6..ee805e1 100644 --- a/libs/gst/helpers/Makefile.am +++ b/libs/gst/helpers/Makefile.am @@ -2,7 +2,7 @@ helpers_PROGRAMS = gst-plugin-scanner helpersdir=$(libexecdir)/gstreamer-$(GST_MAJORMINOR) gst_plugin_scanner_SOURCES = gst-plugin-scanner.c -gst_plugin_scanner_CFLAGS = $(GST_OBJ_CFLAGS) +gst_plugin_scanner_CFLAGS = $(GST_OBJ_CFLAGS) -pie gst_plugin_scanner_LDADD = $(GST_OBJ_LIBS) Android.mk: Makefile.am diff --git a/packaging/gstreamer-registry.service b/packaging/gstreamer-registry.service new file mode 100644 index 0000000..fe6e74b --- /dev/null +++ b/packaging/gstreamer-registry.service @@ -0,0 +1,14 @@ +[Unit] +Description=GStreamer Registry +ConditionPathExists=!/home/app/.gstreamer-0.10/registry.bin + +[Service] +Type=oneshot +Environment=GST_REGISTRY=/home/app/.gstreamer-0.10/registry.bin +User=app +Group=app +ExecStartPre=/bin/mkdir -p /home/app/.gstreamer-0.10 +ExecStart=/usr/bin/gst-inspect-0.10 + +[Install] +WantedBy=multi-user.target diff --git a/packaging/gstreamer.spec b/packaging/gstreamer.spec index 666f7cd..0689149 100644 --- a/packaging/gstreamer.spec +++ b/packaging/gstreamer.spec @@ -1,15 +1,16 @@ Name: gstreamer Summary: GStreamer streaming media framework runtime -Version: 0.10.36 -Release: 2 +Version: 0.10.37 +Release: 44 Group: Applications/Multimedia -License: LGPLv2+ +License: LGPL-2.0+ Source0: %{name}-%{version}.tar.gz +Source1: gstreamer-registry.service Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libxml-2.0) -BuildRequires: pkgconfig(mm-ta) +BuildRequires: pkgconfig(dlog) BuildRequires: bison BuildRequires: flex @@ -54,11 +55,18 @@ with different major/minor versions of GStreamer. %build +./autogen.sh --noconfigure + export CFLAGS+=" -Wall -g -fPIC\ -DGST_EXT_AV_RECORDING\ -DGST_EXT_QUEUE_ENHANCEMENT\ + -DGST_EXT_MQ_MODIFICATION\ -DGST_EXT_CURRENT_BYTES\ - -DGST_EXT_MODIFIED_DQBUF" + -DGST_EXT_BASEPARSER_MODIFICATION\ + -DGST_EXT_BASIC_MODIFICATION\ + -D_VSP_SPEED_\ + -DGST_EXT_DATA_QUEUE_MODIFICATION\ + -DGST_EXT_BASEPARSE_ENABLE_WFD" %configure --prefix=/usr\ --disable-valgrind\ @@ -76,12 +84,21 @@ export CFLAGS+=" -Wall -g -fPIC\ --disable-gtk-doc\ --disable-registry-update\ --disable-loadsave\ - --with-html-dir=/tmp/dump + --with-html-dir=/tmp/dump\ + --enable-dlog + +make -v make %{?jobs:-j%jobs} %install rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +cp COPYING %{buildroot}/usr/share/license/%{name} +mkdir -p %{buildroot}%{_libdir}/systemd/system +install -m 644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/gstreamer-registry.service +mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants +ln -s ../gstreamer-registry.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/gstreamer-registry.service %make_install rm -rf %{buildroot}/tmp/dump @@ -102,6 +119,7 @@ rm -rf %{buildroot}/tmp/dump %files +%manifest gstreamer.manifest %defattr(-,root,root,-) %doc AUTHORS COPYING NEWS README RELEASE TODO %{_libdir}/libgstreamer-0.10.so.* @@ -125,7 +143,9 @@ rm -rf %{buildroot}/tmp/dump %doc %{_mandir}/man1/gst-launch-0.10.* %doc %{_mandir}/man1/gst-typefind-0.10.* %doc %{_mandir}/man1/gst-xmlinspect-0.10.* - +/usr/share/license/%{name} +%{_libdir}/systemd/system/gstreamer-registry.service +%{_libdir}/systemd/system/multi-user.target.wants/gstreamer-registry.service %files devel %defattr(-,root,root,-) @@ -152,6 +172,7 @@ rm -rf %{buildroot}/tmp/dump %{_libdir}/pkgconfig/gstreamer-net-0.10.pc %files tools +%manifest gstreamer-tools.manifest %defattr(-,root,root,-) %{_bindir}/gst-feedback %{_bindir}/gst-inspect diff --git a/pkgconfig/gstreamer-base.pc.in b/pkgconfig/gstreamer-base.pc.in index 568c454..104cb91 100644 --- a/pkgconfig/gstreamer-base.pc.in +++ b/pkgconfig/gstreamer-base.pc.in @@ -12,4 +12,4 @@ Description: Base classes for GStreamer elements Requires: gstreamer-@GST_MAJORMINOR@ Version: @VERSION@ Libs: -L${libdir} -lgstbase-@GST_MAJORMINOR@ -Cflags: -I${includedir} -DGST_EXT_MODIFIED_DQBUF +Cflags: -I${includedir} -DGST_EXT_BASEPARSER_MODIFICATION diff --git a/plugins/elements/gstfilesink.c b/plugins/elements/gstfilesink.c index d612f0d..0ff429e 100644 --- a/plugins/elements/gstfilesink.c +++ b/plugins/elements/gstfilesink.c @@ -66,6 +66,10 @@ #include #endif +#ifdef GST_EXT_AV_RECORDING +#include /* for posix_fadvise */ +#endif /* GST_EXT_AV_RECORDING */ + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -607,8 +611,14 @@ gst_file_sink_event (GstBaseSink * sink, GstEvent * event) break; } case GST_EVENT_EOS: +#ifdef GST_EXT_AV_RECORDING + GST_WARNING_OBJECT(filesink, "GST_EVENT_EOS received"); +#endif /* GST_EXT_AV_RECORDING */ if (fflush (filesink->file)) goto flush_failed; +#ifdef GST_EXT_AV_RECORDING + GST_WARNING_OBJECT(filesink, "fflush done"); +#endif /* GST_EXT_AV_RECORDING */ break; default: break; @@ -662,6 +672,9 @@ gst_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) GstFileSink *filesink; guint size; guint8 *data; +#ifdef GST_EXT_AV_RECORDING + int ret = 0; +#endif /* GST_EXT_AV_RECORDING */ filesink = GST_FILE_SINK (sink); @@ -676,6 +689,12 @@ gst_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) goto handle_error; filesink->current_pos += size; +#ifdef GST_EXT_AV_RECORDING + ret = posix_fadvise(fileno((FILE *)filesink->file), 0, 0, POSIX_FADV_DONTNEED); + if (ret) { + GST_WARNING_OBJECT(filesink, "posix_fadvise failed : ret %x", ret); + } +#endif /* GST_EXT_AV_RECORDING */ } return GST_FLOW_OK; diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index 87402c8..64115e6 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -909,6 +909,27 @@ gst_file_src_query (GstBaseSrc * basesrc, GstQuery * query) gst_query_set_uri (query, src->uri); ret = TRUE; break; + case GST_QUERY_CUSTOM: { + GstStructure *s; + gchar * file_path; + s = gst_query_get_structure (query); + if (gst_structure_has_name (s, "FileSrcURI")) { + gchar *uri; + GValue value = { 0 }; + + g_value_init (&value, G_TYPE_STRING); + file_path = g_strdup_printf ("%s://%s", "file", src->filename); + g_value_set_string (&value, file_path); + + GST_INFO_OBJECT (src, "Received supported custom query"); + gst_structure_set_value (s, "file-uri", &value); + ret = TRUE; + } else { + GST_WARNING_OBJECT (src,"Unsupported query"); + ret = FALSE; + } + break; + } default: ret = FALSE; break; diff --git a/plugins/elements/gstmultiqueue.c b/plugins/elements/gstmultiqueue.c old mode 100644 new mode 100755 index 0054715..02dfc08 --- a/plugins/elements/gstmultiqueue.c +++ b/plugins/elements/gstmultiqueue.c @@ -91,7 +91,7 @@ * * The default queue size limits are 5 buffers, 10MB of data, or * two second worth of data, whichever is reached first. Note that the number - * of buffers will dynamically grow depending on the fill level of + * of buffers will dynamically grow depending on the fill level of * other queues. * * @@ -229,6 +229,8 @@ enum #define DEFAULT_EXTRA_SIZE_BUFFERS 5 #define DEFAULT_EXTRA_SIZE_TIME 3 * GST_SECOND +#define INCREASE_WINDOW 1 * 1024 * 1024 + #define DEFAULT_USE_BUFFERING FALSE #define DEFAULT_LOW_PERCENT 10 #define DEFAULT_HIGH_PERCENT 99 @@ -243,6 +245,9 @@ enum PROP_MAX_SIZE_BYTES, PROP_MAX_SIZE_BUFFERS, PROP_MAX_SIZE_TIME, +#ifdef GST_EXT_MQ_MODIFICATION + PROP_CURR_SIZE_BYTES, +#endif PROP_USE_BUFFERING, PROP_LOW_PERCENT, PROP_HIGH_PERCENT, @@ -328,7 +333,7 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) * size) is higher than the boundary values which can be set through the * GObject properties. * - * This can be used as an indicator of pre-roll. + * This can be used as an indicator of pre-roll. */ gst_multi_queue_signals[SIGNAL_OVERRUN] = g_signal_new ("overrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, @@ -351,7 +356,13 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) g_param_spec_uint64 ("max-size-time", "Max. size (ns)", "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64, DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - +#ifdef GST_EXT_MQ_MODIFICATION + g_object_class_install_property (gobject_class, PROP_CURR_SIZE_BYTES, + g_param_spec_uint ("curr-size-bytes", "Current buffered size (kB)", + "buffered amount of data in the queue (bytes)", + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +#endif g_object_class_install_property (gobject_class, PROP_EXTRA_SIZE_BYTES, g_param_spec_uint ("extra-size-bytes", "Extra Size (kB)", "Amount of data the queues can grow if one of them is empty (bytes, 0=disable)" @@ -373,7 +384,7 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) /** * GstMultiQueue:use-buffering - * + * * Enable the buffering option in multiqueue so that BUFFERING messages are * emited based on low-/high-percent thresholds. * @@ -385,7 +396,7 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstMultiQueue:low-percent - * + * * Low threshold percent for buffering to start. * * Since: 0.10.26 @@ -396,7 +407,7 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) DEFAULT_LOW_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstMultiQueue:high-percent - * + * * High threshold percent for buffering to finish. * * Since: 0.10.26 @@ -408,7 +419,7 @@ gst_multi_queue_class_init (GstMultiQueueClass * klass) /** * GstMultiQueue:sync-by-running-time - * + * * If enabled multiqueue will synchronize deactivated or not-linked streams * to the activated and linked streams by taking the running time. * Otherwise multiqueue will synchronize the deactivated or not-linked @@ -537,6 +548,35 @@ gst_multi_queue_set_property (GObject * object, guint prop_id, } } +#ifdef GST_EXT_MQ_MODIFICATION +static guint +get_current_size_bytes (GstMultiQueue * mq) +{ + GList *tmp; + GstClockTime highest = GST_CLOCK_TIME_NONE; + GstClockTime lowest = GST_CLOCK_TIME_NONE; + guint current_size_bytes = 0; + + for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) { + GstSingleQueue *sq = (GstSingleQueue *) tmp->data; + GstDataQueueSize size; + + gst_data_queue_get_level (sq->queue, &size); + + current_size_bytes += size.bytes; + + GST_DEBUG_OBJECT (mq, + "queue %d: bytes %u/%u, time %" G_GUINT64_FORMAT "/%" + G_GUINT64_FORMAT, sq->id, size.bytes, sq->max_size.bytes, + sq->cur_time, sq->max_size.time); + } + + GST_INFO_OBJECT (mq, "current_size_bytes : %u", current_size_bytes); + + return current_size_bytes; +} +#endif + static void gst_multi_queue_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -564,6 +604,11 @@ gst_multi_queue_get_property (GObject * object, guint prop_id, case PROP_MAX_SIZE_TIME: g_value_set_uint64 (value, mq->max_size.time); break; +#ifdef GST_EXT_MQ_MODIFICATION + case PROP_CURR_SIZE_BYTES: + g_value_set_uint (value, get_current_size_bytes(mq)); + break; +#endif case PROP_USE_BUFFERING: g_value_set_boolean (value, mq->use_buffering); break; @@ -801,10 +846,22 @@ update_buffering (GstMultiQueue * mq, GstSingleQueue * sq) gint percent, tmp; gboolean post = FALSE; - /* nothing to dowhen we are not in buffering mode */ + /* nothing to do when we are not in buffering mode */ if (!mq->use_buffering) return; +#ifdef GST_EXT_MQ_MODIFICATION + GstCaps *caps = GST_PAD_CAPS(sq->sinkpad); + GstStructure *s; + + /* skip checking the text queue. */ + if ((caps) && + (s = gst_caps_get_structure (caps, 0)) && + (g_strrstr (gst_structure_get_name (s), "text"))) { + return; + } +#endif + gst_data_queue_get_level (sq->queue, &size); GST_DEBUG_OBJECT (mq, @@ -812,6 +869,9 @@ update_buffering (GstMultiQueue * mq, GstSingleQueue * sq) G_GUINT64_FORMAT, sq->id, size.visible, sq->max_size.visible, size.bytes, sq->max_size.bytes, sq->cur_time, sq->max_size.time); + GST_INFO_OBJECT (mq, "queue %d: cached time %u sec, byte %u", + sq->id, (guint)(sq->cur_time/GST_SECOND), size.bytes); + /* get bytes and time percentages and take the max */ if (sq->is_eos) { percent = 100; @@ -835,12 +895,15 @@ update_buffering (GstMultiQueue * mq, GstSingleQueue * sq) /* make sure it increases */ percent = MAX (mq->percent, percent); +#ifndef GST_EXT_MQ_MODIFICATION if (percent == mq->percent) /* don't post if nothing changed */ post = FALSE; else /* else keep last value we posted */ - mq->percent = percent; +#endif + mq->percent = percent; + } else { if (percent < mq->low_percent) { mq->buffering = TRUE; @@ -867,7 +930,7 @@ update_buffering (GstMultiQueue * mq, GstSingleQueue * sq) } /* calculate the diff between running time on the sink and src of the queue. - * This is the total amount of time in the queue. + * This is the total amount of time in the queue. * WITH LOCK TAKEN */ static void update_time_level (GstMultiQueue * mq, GstSingleQueue * sq) @@ -964,7 +1027,7 @@ apply_buffer (GstMultiQueue * mq, GstSingleQueue * sq, GstClockTime timestamp, { GST_MULTI_QUEUE_MUTEX_LOCK (mq); - /* if no timestamp is set, assume it's continuous with the previous + /* if no timestamp is set, assume it's continuous with the previous * time */ if (timestamp == GST_CLOCK_TIME_NONE) timestamp = segment->last_stop; @@ -1215,8 +1278,8 @@ gst_multi_queue_loop (GstPad * pad) /* If we're not-linked, we do some extra work because we might need to * wait before pushing. If we're linked but there's a gap in the IDs, - * or it's the first loop, or we just passed the previous highid, - * we might need to wake some sleeping pad up, so there's extra work + * or it's the first loop, or we just passed the previous highid, + * we might need to wake some sleeping pad up, so there's extra work * there too */ if (sq->srcresult == GST_FLOW_NOT_LINKED || (sq->last_oldid == G_MAXUINT32) || (newid != (sq->last_oldid + 1)) @@ -1695,7 +1758,7 @@ compute_high_id (GstMultiQueue * mq) lowest = sq->nextid; } else if (sq->srcresult != GST_FLOW_UNEXPECTED) { /* If we don't have a global highid, or the global highid is lower than - * this single queue's last outputted id, store the queue's one, + * this single queue's last outputted id, store the queue's one, * unless the singlequeue is at EOS (srcresult = UNEXPECTED) */ if ((highid == G_MAXUINT32) || (sq->oldid > highid)) highid = sq->oldid; @@ -1740,7 +1803,7 @@ compute_high_time (GstMultiQueue * mq) lowest = sq->next_time; } else if (sq->srcresult != GST_FLOW_UNEXPECTED) { /* If we don't have a global highid, or the global highid is lower than - * this single queue's last outputted id, store the queue's one, + * this single queue's last outputted id, store the queue's one, * unless the singlequeue is at EOS (srcresult = UNEXPECTED) */ if (highest == GST_CLOCK_TIME_NONE || sq->last_time > highest) highest = sq->last_time; @@ -1772,6 +1835,14 @@ single_queue_overrun_cb (GstDataQueue * dq, GstSingleQueue * sq) GST_LOG_OBJECT (mq, "Single Queue %d is full", sq->id); + if(mq->max_size.bytes < DEFAULT_EXTRA_SIZE_BYTES) { + GST_LOG_OBJECT (mq, "increasing the queue size"); + GST_MULTI_QUEUE_MUTEX_LOCK (mq); + mq->max_size.bytes = mq->max_size.bytes + INCREASE_WINDOW; + SET_CHILD_PROPERTY (mq, bytes); + GST_MULTI_QUEUE_MUTEX_UNLOCK (mq); + } + GST_MULTI_QUEUE_MUTEX_LOCK (mq); for (tmp = mq->queues; tmp; tmp = g_list_next (tmp)) { GstSingleQueue *oq = (GstSingleQueue *) tmp->data; diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 095df6d..9615ff8 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -1551,8 +1551,21 @@ gst_queue_set_property (GObject * object, break; #ifdef GST_EXT_AV_RECORDING case PROP_EMPTY_BUFFERS: - queue->empty_buffers = g_value_get_boolean (value); + { + gboolean empty_buffers = g_value_get_boolean (value); + + GST_INFO("set empty buffer : %d", empty_buffers); + + if (empty_buffers) { + GST_INFO("flush queue"); + gst_queue_locked_flush(queue); + } + + queue->empty_buffers = empty_buffers; + + GST_INFO("done"); break; + } #endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/plugins/elements/gstqueue2.c b/plugins/elements/gstqueue2.c index d84ac4e..10b7051 100755 --- a/plugins/elements/gstqueue2.c +++ b/plugins/elements/gstqueue2.c @@ -66,7 +66,9 @@ #include "gst/glib-compat-private.h" #include - +#ifdef GST_EXT_QUEUE_ENHANCEMENT +#include +#endif #ifdef G_OS_WIN32 #include /* lseek, open, close, read */ #undef lseek @@ -127,7 +129,14 @@ enum #endif #define DEFAULT_RING_BUFFER_MAX_SIZE 0 #ifdef GST_EXT_QUEUE_ENHANCEMENT -#define DEFAULT_FILE_BUFFER_MAX_SIZE 0 +#define DEFAULT_FILE_BUFFER_MAX_SIZE 0 + +#define MAX_NUM_OF_BUFFER_PAD 4 +#define DEFAULT_BUFFER_PAD_SIZE (256*1024) +#define DEFAULT_CURRENT_LEVEL_PAD_SIZE (50*1024) + +guint64 buffer_pad_size[MAX_NUM_OF_BUFFER_PAD] = + {(1.5*1024*1024), (1*1024*1024), (512*1024), (256*1024)}; #endif enum @@ -279,6 +288,11 @@ static gboolean gst_queue2_is_filled (GstQueue2 * queue); static void update_cur_level (GstQueue2 * queue, GstQueue2Range * range); +#ifdef GST_EXT_QUEUE_ENHANCEMENT +static void gst_queue2_update_buffer_pad_size(GstQueue2 * queue); +static gboolean change_current_range(GstQueue2 * queue, GstQueue2Range *req_range, guint64 offset, guint length); +#endif + typedef enum { GST_QUEUE2_ITEM_TYPE_UNKNOWN = 0, @@ -526,6 +540,8 @@ gst_queue2_init (GstQueue2 * queue, GstQueue2Class * g_class) queue->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE; #ifdef GST_EXT_QUEUE_ENHANCEMENT queue->file_buffer_max_size = DEFAULT_FILE_BUFFER_MAX_SIZE; + queue->buffer_pad_size = DEFAULT_BUFFER_PAD_SIZE; + queue->latest_seek_pos = 0; #endif GST_DEBUG_OBJECT (queue, @@ -571,7 +587,7 @@ debug_ranges (GstQueue2 * queue) "range [%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "] (rb [%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "])(fb [%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "]), reading %" G_GUINT64_FORMAT - " current range? %s", walk->offset, walk->writing_pos, walk->rb_offset, walk->rb_writing_pos, + " current range? %s", walk->offset, walk->writing_pos, walk->rb_offset, walk->rb_writing_pos, walk->fb_offset, walk->fb_writing_pos, walk->reading_pos, walk == queue->current ? "**y**" : " n "); #else @@ -961,6 +977,11 @@ update_buffering (GstQueue2 * queue) } else { percent = GET_PERCENT (bytes, 0); } + + GST_DEBUG_OBJECT (queue, "bytes filled %d percent", (gint) percent); + GST_DEBUG_OBJECT (queue, "time filled %d percent", GET_PERCENT (time, 0)); + GST_DEBUG_OBJECT (queue, "buffers filled %d percent", GET_PERCENT (buffers, 0)); + GST_DEBUG_OBJECT (queue, "filled %d percent", GET_PERCENT (rate_time, 0)); #else if (!QUEUE_IS_USING_RING_BUFFER (queue)) { percent = GET_PERCENT (bytes, 0); @@ -1110,8 +1131,10 @@ update_in_rates (GstQueue2 * queue) queue->cur_level.rate_time = queue->cur_level.bytes / queue->byte_in_rate * GST_SECOND; } + GST_DEBUG_OBJECT (queue, "rates: in %f, time %" GST_TIME_FORMAT, queue->byte_in_rate, GST_TIME_ARGS (queue->cur_level.rate_time)); + GST_INFO_OBJECT (queue, "byte_in_rate : %.2f KBps", (queue->byte_in_rate/1024)); } static void @@ -1176,11 +1199,20 @@ static gboolean perform_seek_to_offset (GstQueue2 * queue, guint64 offset) { GstEvent *event; - gboolean res; + gboolean res = TRUE; GST_QUEUE2_MUTEX_UNLOCK (queue); - GST_DEBUG_OBJECT (queue, "Seeking to %" G_GUINT64_FORMAT, offset); +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if (queue->latest_seek_pos == offset) { + GST_DEBUG_OBJECT (queue, "Duplicated request to %" G_GUINT64_FORMAT", in: %f", offset, queue->byte_in_rate); + GST_QUEUE2_MUTEX_LOCK (queue); + return res; + } else { + GST_INFO_OBJECT (queue, "Seeking to %" G_GUINT64_FORMAT", in: %f", offset, queue->byte_in_rate); + } + queue->latest_seek_pos = offset; +#endif event = gst_event_new_seek (1.0, GST_FORMAT_BYTES, @@ -1204,6 +1236,66 @@ perform_seek_to_offset (GstQueue2 * queue, guint64 offset) return res; } +#ifdef GST_EXT_QUEUE_ENHANCEMENT +static void +gst_queue2_update_buffer_pad_size(GstQueue2 * queue) +{ + guint idx = 0; + + for (idx=0 ; idx < MAX_NUM_OF_BUFFER_PAD ; idx++) { + if ((guint64)queue->byte_in_rate > buffer_pad_size[idx]) + break; + } + + if (idx < MAX_NUM_OF_BUFFER_PAD) + queue->buffer_pad_size = buffer_pad_size[idx]; + else + queue->buffer_pad_size = DEFAULT_BUFFER_PAD_SIZE; + + GST_DEBUG_OBJECT(queue, "new pad size = %lld", queue->buffer_pad_size); +} + +/* To reduce http server connection we do not change current range repeatedly. */ +static gboolean +change_current_range(GstQueue2 * queue, GstQueue2Range *req_range, guint64 offset, guint length) +{ + guint64 curr_level = 0; + guint64 curr_min_level = 0; + + if (queue->current->writing_pos > queue->current->reading_pos) + curr_level = queue->current->writing_pos - queue->current->reading_pos; + + gst_queue2_update_buffer_pad_size (queue); + curr_min_level = MIN((queue->max_level.bytes*0.05), DEFAULT_CURRENT_LEVEL_PAD_SIZE); + + GST_DEBUG_OBJECT(queue, " curr[w%"G_GUINT64_FORMAT", r%"G_GUINT64_FORMAT + ", d%"G_GUINT64_FORMAT", m%"G_GUINT64_FORMAT + "] u[%"G_GUINT64_FORMAT"] [%s]", + queue->current->writing_pos, queue->current->reading_pos, + curr_level, curr_min_level, + queue->upstream_size, (queue->is_eos)?"EOS":"---"); + + if ((queue->is_eos) || + (queue->current->writing_pos >= queue->upstream_size)) + return TRUE; + + if ((queue->current->writing_pos < req_range->writing_pos) + && (offset+length < (queue->current->writing_pos + queue->buffer_pad_size))) + return FALSE; + + if (curr_level >= curr_min_level) + { + GST_DEBUG_OBJECT (queue, "Range Switching"); + return TRUE; + } + else + { + GST_DEBUG_OBJECT (queue, "No Switching.. keep receiving data in the same range.."); + return FALSE; + } +} +#endif + /* see if there is enough data in the file to read a full buffer */ static gboolean gst_queue2_have_data (GstQueue2 * queue, guint64 offset, guint length) @@ -1216,11 +1308,28 @@ gst_queue2_have_data (GstQueue2 * queue, guint64 offset, guint length) if ((range = find_range (queue, offset))) { if (queue->current != range) { GST_DEBUG_OBJECT (queue, "switching ranges, do seek to range position"); + +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if ((QUEUE_IS_USING_RING_BUFFER (queue)) || + (QUEUE_IS_USING_FILE_RING_BUFFER (queue)) || + (change_current_range(queue, range, offset, length))) + { + perform_seek_to_offset (queue, range->writing_pos); + } + + if (offset + length <= range->writing_pos) + return TRUE; + else + return FALSE; + +#else perform_seek_to_offset (queue, range->writing_pos); +#endif + #ifdef GST_EXT_QUEUE_ENHANCEMENT return FALSE; #endif - } + } GST_INFO_OBJECT (queue, "cur_level.bytes %u (max %" G_GUINT64_FORMAT ")", queue->cur_level.bytes, QUEUE_MAX_BYTES (queue)); @@ -1272,9 +1381,16 @@ gst_queue2_have_data (GstQueue2 * queue, guint64 offset, guint length) "requested data is within range, wait for data"); return FALSE; } - } else if (offset > queue->current->writing_pos && offset < queue->current->writing_pos + 200000) { - GST_INFO_OBJECT (queue, "wait for data"); - return FALSE; + } else { + + gst_queue2_update_buffer_pad_size (queue); + + if (offset > queue->current->writing_pos && offset < queue->current->writing_pos + queue->buffer_pad_size) { + GST_INFO_OBJECT (queue, "wait for data"); + update_cur_pos (queue, queue->current, offset + length); + update_in_rates (queue); + return FALSE; + } } #else } else if (offset < queue->current->writing_pos + 200000) { @@ -1307,6 +1423,10 @@ gst_queue2_read_data_at_offset (GstQueue2 * queue, guint64 offset, guint length, guint8 *ring_buffer; size_t res; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + int ret = 0; +#endif + ring_buffer = queue->ring_buffer; if (QUEUE_IS_USING_TEMP_FILE (queue) && FSEEK_FILE (queue->temp_file, offset)) @@ -1317,6 +1437,13 @@ gst_queue2_read_data_at_offset (GstQueue2 * queue, guint64 offset, guint length, length, offset); if (QUEUE_IS_USING_TEMP_FILE (queue)) { res = fread (dst, 1, length, queue->temp_file); + /* [queue2]add posix_fadvise because of page cache free after streaming */ + #ifdef GST_EXT_QUEUE_ENHANCEMENT + ret = posix_fadvise(fileno((FILE *)queue->temp_file), 0, 0, POSIX_FADV_DONTNEED); + if (ret != 0){ + GST_WARNING_OBJECT(queue,"posix_fadvise failed : ret %x",ret); + } + #endif } else { memcpy (dst, ring_buffer + offset, length); res = length; @@ -1366,6 +1493,7 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, guint64 rpos; #ifdef GST_EXT_QUEUE_ENHANCEMENT guint64 fb_size; + GstQueue2Range* read_range = NULL; #endif /* allocate the output buffer of the requested size */ @@ -1383,6 +1511,12 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, remaining = length; while (remaining > 0) { + +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if(!(read_range = find_range (queue, offset))) + read_range = queue->current; +#endif + /* configure how much/whether to read */ if (!gst_queue2_have_data (queue, rpos, remaining)) { read_length = 0; @@ -1446,7 +1580,14 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, queue->current->max_reading_pos = rpos; update_cur_level (queue, queue->current); } + + /* update the buffering */ + if (queue->use_buffering) + { + update_buffering (queue); + } #endif + GST_DEBUG_OBJECT (queue, "waiting for add"); GST_QUEUE2_WAIT_ADD_CHECK (queue, queue->srcresult, out_flushing); continue; @@ -1457,7 +1598,15 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, } /* set range reading_pos to actual reading position for this read */ +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if((!QUEUE_IS_USING_RING_BUFFER (queue)) && + (!QUEUE_IS_USING_FILE_RING_BUFFER(queue))) + read_range->reading_pos = rpos; + else + read_range->reading_pos = rpos; +#else queue->current->reading_pos = rpos; +#endif /* configure how much and from where to read */ if (QUEUE_IS_USING_RING_BUFFER (queue)) { @@ -1472,8 +1621,8 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, #ifdef GST_EXT_QUEUE_ENHANCEMENT } else if (QUEUE_IS_USING_FILE_RING_BUFFER(queue)){ file_offset = - (queue->current->fb_offset + (rpos - - queue->current->offset)) % fb_size; + (read_range->fb_offset + (rpos - + read_range->offset)) % fb_size; if (file_offset + read_length > fb_size) { block_length = fb_size - file_offset; @@ -1507,8 +1656,22 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, block_length = read_length; remaining -= read_return; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if((!QUEUE_IS_USING_RING_BUFFER (queue)) && + (!QUEUE_IS_USING_FILE_RING_BUFFER(queue))) + { + rpos = (read_range->reading_pos += read_return); + update_cur_pos (queue, read_range, read_range->reading_pos); + } + else + { + rpos = (read_range->reading_pos += read_return); + update_cur_pos (queue, read_range, read_range->reading_pos); + } +#else rpos = (queue->current->reading_pos += read_return); update_cur_pos (queue, queue->current, queue->current->reading_pos); +#endif } GST_QUEUE2_SIGNAL_DEL (queue); GST_DEBUG_OBJECT (queue, "%u bytes left to read", remaining); @@ -1520,6 +1683,12 @@ gst_queue2_create_read (GstQueue2 * queue, guint64 offset, guint length, *buffer = buf; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + /* update the buffering */ + if (queue->use_buffering) + update_buffering (queue); +#endif + return GST_FLOW_OK; /* ERRORS */ @@ -1772,7 +1941,10 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) guint64 writing_pos, new_writing_pos; GstQueue2Range *range, *prev, *next; #ifdef GST_EXT_QUEUE_ENHANCEMENT - guint fb_size; + guint64 merged_writing_pos = 0; + guint64 merged_max_read_pos = 0; + + guint64 fb_size; #endif if (QUEUE_IS_USING_RING_BUFFER (queue)) @@ -1914,7 +2086,7 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) #ifdef GST_EXT_QUEUE_ENHANCEMENT else if (QUEUE_IS_USING_FILE_RING_BUFFER(queue)) { gint64 space; - + /* calculate the space in the ring buffer not used by data from * the current range */ while (queue->file_buffer_max_size <= queue->cur_level.bytes + 1024*200) { @@ -2027,7 +2199,7 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) } } #endif - else { + else { to_write = size; new_writing_pos = writing_pos + to_write; } @@ -2079,6 +2251,10 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) * is a lot of data in the range we merged with to avoid reading it all * again. */ queue->current->next = next->next; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + merged_writing_pos = next->writing_pos; + merged_max_read_pos = next->max_reading_pos; +#endif g_slice_free (GstQueue2Range, next); debug_ranges (queue); @@ -2144,6 +2320,21 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) #endif } else { queue->current->writing_pos = writing_pos = new_writing_pos; + +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if (merged_writing_pos != 0) { + if (queue->current->writing_pos + (50*1024) < merged_writing_pos) { + queue->current->writing_pos = merged_writing_pos; + queue->current->max_reading_pos = merged_max_read_pos; + GST_INFO_OBJECT (queue, "merged writing position : %lld, read: %lld", merged_writing_pos, merged_max_read_pos); + perform_seek_to_offset(queue, queue->current->writing_pos); + } else { + GST_INFO_OBJECT (queue, "keep waiting."); + if (queue->current->writing_pos < merged_max_read_pos) + queue->current->max_reading_pos = queue->current->writing_pos; + } + } +#endif } update_cur_level (queue, queue->current); @@ -2155,7 +2346,7 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer) queue->cur_level.bytes, QUEUE_MAX_BYTES (queue)); GST_QUEUE2_SIGNAL_ADD (queue); - }; + } return TRUE; @@ -2988,6 +3179,126 @@ gst_queue2_peer_query (GstQueue2 * queue, GstPad * pad, GstQuery * query) return ret; } +#ifdef GST_EXT_QUEUE_ENHANCEMENT +static gboolean +gst_queue2_handle_buffering_query(GstQueue2 *queue, GstQuery * query) +{ + GstFormat format; + gint64 start, stop, range_start, range_stop; + gint percent; + gint64 estimated_total, buffering_left; + GstFormat peer_fmt; + gint64 duration; + gboolean peer_res, is_buffering, is_eos; + gdouble byte_in_rate, byte_out_rate; + gint64 peer_pos; + + byte_in_rate = queue->byte_in_rate; + byte_out_rate = queue->byte_out_rate; + is_buffering = queue->is_buffering; + is_eos = queue->is_eos; + percent = queue->buffering_percent; + + GST_DEBUG_OBJECT (queue, "byte_in_rate %f", byte_in_rate); + GST_DEBUG_OBJECT (queue, "byte_out_rate %f", byte_out_rate); + GST_DEBUG_OBJECT (queue, "percent %d", percent); + GST_DEBUG_OBJECT (queue, "eos? %s, buffering? %s", (is_eos)?"OO":"XX", (is_buffering)?"OO":"XX"); + + /* get duration of upstream in bytes */ + peer_fmt = GST_FORMAT_BYTES; + peer_res = gst_pad_query_peer_duration (queue->sinkpad, &peer_fmt, &duration); + if (peer_res) + peer_res = gst_pad_query_peer_position(queue->sinkpad, &peer_fmt, &peer_pos); + + GST_DEBUG_OBJECT (queue, "duration %lld, peer_pos %lld", duration, peer_pos); + + /* calculate remaining and total download time */ + if (peer_res && byte_in_rate > 0.0) { + estimated_total = (duration * 1000) / byte_in_rate; + buffering_left = ((duration - peer_pos) * 1000) / byte_in_rate; + } else { + estimated_total = -1; + buffering_left = -1; + } + + GST_DEBUG_OBJECT (queue, "estimated %" G_GINT64_FORMAT ", left %" + G_GINT64_FORMAT, estimated_total, buffering_left); + + gst_query_parse_buffering_range (query, &format, NULL, NULL, NULL); + + switch (format) { + case GST_FORMAT_PERCENT: + /* we need duration */ + if (!peer_res) + return FALSE; + + /* get our available data relative to the duration */ + if (duration != -1 && duration != 0) + { + GST_DEBUG_OBJECT (queue, "cur_level byte %d", queue->cur_level.bytes); + GST_DEBUG_OBJECT (queue, "cur_level buffers %d", queue->cur_level.buffers); + GST_DEBUG_OBJECT (queue, "cur_level time %lld", queue->cur_level.time); + + start = GST_FORMAT_PERCENT_MAX * (peer_pos - queue->cur_level.bytes) / duration; + stop = GST_FORMAT_PERCENT_MAX * peer_pos / duration; + } + else + { + start = 0; + stop = -1; + } + + GST_DEBUG_OBJECT (queue, "start %lld, stop %lld", start, stop); + break; + case GST_FORMAT_BYTES: + start = 0; + stop = peer_pos; + break; + + default: + start = -1; + stop = -1; + break; + } + + /* fill out the buffered ranges */ + switch (format) { + case GST_FORMAT_PERCENT: + if (duration == -1 || duration ==0) { + range_start = 0; + range_stop = 0; + break; + } + + range_start = 100 * (peer_pos - queue->cur_level.bytes) / duration; + range_stop = 100 * peer_pos / duration; + break; + case GST_FORMAT_BYTES: + range_start = (peer_pos - queue->cur_level.bytes); + range_stop = peer_pos; + break; + default: + range_start = -1; + range_stop = -1; + break; + } + + GST_DEBUG_OBJECT (queue, + "range starting at %" G_GINT64_FORMAT " and finishing at %" + G_GINT64_FORMAT, range_start, range_stop); + + gst_query_add_buffering_range (query, range_start, range_stop); + + gst_query_set_buffering_percent (query, is_buffering, percent); + gst_query_set_buffering_range (query, format, start, stop, + estimated_total); + gst_query_set_buffering_stats (query, GST_BUFFERING_DOWNLOAD, + byte_in_rate, byte_out_rate, buffering_left); + + return TRUE; +} +#endif + static gboolean gst_queue2_handle_src_query (GstPad * pad, GstQuery * query) { @@ -3044,10 +3355,15 @@ gst_queue2_handle_src_query (GstPad * pad, GstQuery * query) /* FIXME - is this condition correct? what should ring buffer do? */ if (QUEUE_IS_USING_QUEUE (queue)) { +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if (!gst_queue2_handle_buffering_query(queue, query)) + goto peer_failed; +#else /* no temp file, just forward to the peer */ if (!gst_queue2_peer_query (queue, queue->sinkpad, query)) goto peer_failed; GST_DEBUG_OBJECT (queue, "buffering forwarded to peer"); +#endif } else { gint64 start, stop, range_start, range_stop; guint64 writing_pos; @@ -3085,6 +3401,10 @@ gst_queue2_handle_src_query (GstPad * pad, GstQuery * query) if (peer_res && byte_in_rate > 0.0) { estimated_total = (duration * 1000) / byte_in_rate; buffering_left = ((duration - writing_pos) * 1000) / byte_in_rate; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if (is_eos) + buffering_left = 0; +#endif } else { estimated_total = -1; buffering_left = -1; @@ -3135,7 +3455,12 @@ gst_queue2_handle_src_query (GstPad * pad, GstQuery * query) range_stop = 100 * queued_ranges->writing_pos / duration; break; case GST_FORMAT_BYTES: - range_start = queued_ranges->offset; +#ifdef GST_EXT_QUEUE_ENHANCEMENT + if (queued_ranges->reading_pos > 0) + range_start = queued_ranges->reading_pos; + else +#endif + range_start = queued_ranges->offset; range_stop = queued_ranges->writing_pos; break; default: diff --git a/plugins/elements/gstqueue2.h b/plugins/elements/gstqueue2.h index 0f429c7..e2ad426 100755 --- a/plugins/elements/gstqueue2.h +++ b/plugins/elements/gstqueue2.h @@ -148,6 +148,8 @@ struct _GstQueue2 gboolean temp_remove; #ifdef GST_EXT_QUEUE_ENHANCEMENT gboolean temp_unlink; + guint64 buffer_pad_size; + guint64 latest_seek_pos; #endif FILE *temp_file; /* list of downloaded areas and the current area */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 46d70fb..5d08baf 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -38,24 +38,24 @@ bin_SCRIPTS = gst-feedback-@GST_MAJORMINOR@ # make sure each versioned tool has the right source file and flags if !GST_DISABLE_LOADSAVE gst_xmllaunch_@GST_MAJORMINOR@_SOURCES = gst-launch.c tools.h -gst_xmllaunch_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -UGST_DISABLE_DEPRECATED +gst_xmllaunch_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -UGST_DISABLE_DEPRECATED -pie gst_xmllaunch_@GST_MAJORMINOR@_LDADD = $(GST_OBJ_LIBS) endif if !GST_DISABLE_PARSE gst_launch_@GST_MAJORMINOR@_SOURCES = gst-launch.c tools.h -gst_launch_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -UGST_DISABLE_DEPRECATED +gst_launch_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -UGST_DISABLE_DEPRECATED -pie gst_launch_@GST_MAJORMINOR@_LDADD = $(GST_OBJ_LIBS) endif gst_inspect_@GST_MAJORMINOR@_SOURCES = gst-inspect.c tools.h -gst_inspect_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) +gst_inspect_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -pie gst_inspect_@GST_MAJORMINOR@_LDADD = $(GST_OBJ_LIBS) gst_typefind_@GST_MAJORMINOR@_SOURCES = gst-typefind.c tools.h -gst_typefind_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) +gst_typefind_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -pie gst_typefind_@GST_MAJORMINOR@_LDADD = $(GST_OBJ_LIBS) gst_xmlinspect_@GST_MAJORMINOR@_SOURCES = gst-xmlinspect.c tools.h -gst_xmlinspect_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) +gst_xmlinspect_@GST_MAJORMINOR@_CFLAGS = $(GST_OBJ_CFLAGS) -pie gst_xmlinspect_@GST_MAJORMINOR@_LDADD = $(GST_OBJ_LIBS) gst-feedback-@GST_MAJORMINOR@: gst-feedback-m.m diff --git a/tools/gst-feedback-m.m b/tools/gst-feedback-m.m index 0365182..aa2ecd7 100755 --- a/tools/gst-feedback-m.m +++ b/tools/gst-feedback-m.m @@ -5,40 +5,40 @@ command_output () { - echo "+++ $1" + /bin/echo "+++ $1" $1 } -echo "GStreamer feedback script." -echo "Please attach the output of this script to your bug reports." -echo "Bug reports should go into Gnome's bugzilla (http://bugzilla.gnome.org)" -echo +/bin/echo "GStreamer feedback script." +/bin/echo "Please attach the output of this script to your bug reports." +/bin/echo "Bug reports should go into Gnome's bugzilla (http://bugzilla.gnome.org)" +/bin/echo -echo "+ SYSTEM INFORMATION" +/bin/echo "+ SYSTEM INFORMATION" command_output "uname -a" if test -f /etc/redhat-release; then - echo "+++ distribution: Red Hat" - cat /etc/redhat-release + /bin/echo "+++ distribution: Red Hat" + /bin/cat /etc/redhat-release fi if test -f /etc/debian_version; then - echo "+++ distribution: Debian" - cat /etc/debian_version + /bin/echo "+++ distribution: Debian" + /bin/cat /etc/debian_version fi command_output "cat /etc/issue" -echo +/bin/echo -echo "+ USER INFORMATION" +/bin/echo "+ USER INFORMATION" command_output "id" -echo +/bin/echo -echo "+ PKG-CONFIG INFORMATION" +/bin/echo "+ PKG-CONFIG INFORMATION" for mm in 0.6 0.7 0.8 do - echo "+ $mm" + /bin/echo "+ $mm" command_output "pkg-config --version" command_output "pkg-config gstreamer-$mm --modversion" 2>/dev/null command_output "pkg-config gstreamer-$mm --cflags" 2>/dev/null @@ -46,7 +46,7 @@ do command_output "pkg-config gstreamer-libs-$mm --modversion" 2>/dev/null command_output "pkg-config gstreamer-libs-$mm --cflags" 2>/dev/null command_output "pkg-config gstreamer-libs-$mm --libs" 2>/dev/null - echo + /bin/echo done for mm in 0.9 0.10 @@ -55,15 +55,15 @@ do gstreamer-dataprotocol gstreamer-plugins-base gstreamer-net\ gst-python do - echo "+ $mm" + /bin/echo "+ $mm" command_output "pkg-config $module-$mm --modversion" 2>/dev/null command_output "pkg-config $module-$mm --cflags" 2>/dev/null command_output "pkg-config $module-$mm --libs" 2>/dev/null - echo + /bin/echo done done -echo "+ GSTREAMER INFORMATION (unversioned)" +/bin/echo "+ GSTREAMER INFORMATION (unversioned)" command_output "which gst-inspect" command_output "gst-inspect" command_output "gst-inspect fakesrc" @@ -71,7 +71,7 @@ command_output "gst-inspect fakesink" command_output "gst-launch fakesrc num-buffers=5 ! fakesink" for mm in 0.6 0.7 0.8 0.9 0.10 do - echo "+ GSTREAMER INFORMATION ($mm)" + /bin/echo "+ GSTREAMER INFORMATION ($mm)" command_output "which gst-inspect-$mm" command_output "gst-inspect-$mm" command_output "gst-inspect-$mm fakesrc" @@ -79,36 +79,36 @@ do command_output "gst-launch-$mm fakesrc num-buffers=5 ! fakesink" done -echo "++ looking for gstreamer libraries in common locations" +/bin/echo "++ looking for gstreamer libraries in common locations" for dirs in /usr/lib /usr/local/lib; do if test -d $dirs; then - find $dirs -name libgstreamer* | grep so + /bin/find $dirs -name libgstreamer* | grep so fi done echo "++ looking for gstreamer headers in common locations" for dirs in /usr/include /usr/local/include; do if test -d $dirs; then - find $dirs -name gst.h + /bin/find $dirs -name gst.h fi done -echo "+ GSTREAMER PLUG-INS INFORMATION" +/bin/echo "+ GSTREAMER PLUG-INS INFORMATION" command_output "gst-inspect volume" for mm in 0.6 0.7 0.8 0.9 0.10 do command_output "gst-inspect-$mm volume" done -echo "++ looking for gstreamer volume plugin in common locations" +/bin/echo "++ looking for gstreamer volume plugin in common locations" for dirs in /usr/lib /usr/local/lib; do if test -d $dirs; then - find $dirs -name libgstvolume* | grep so + /bin/find $dirs -name libgstvolume* | grep so fi done echo "++ looking for gstreamer headers in common locations" for dirs in /usr/include /usr/local/include; do if test -d $dirs; then - find $dirs -name audio.h + /bin/find $dirs -name audio.h fi done diff --git a/win32/common/libgstbase.def b/win32/common/libgstbase.def index e68c0e9..2292ae1 100644 --- a/win32/common/libgstbase.def +++ b/win32/common/libgstbase.def @@ -260,6 +260,7 @@ EXPORTS gst_data_queue_limits_changed gst_data_queue_new gst_data_queue_new_full + gst_data_queue_peek gst_data_queue_pop gst_data_queue_push gst_data_queue_set_flushing -- 2.7.4