From d33c37ba1f63f11e4115de3d1e7a5bd745c99de0 Mon Sep 17 00:00:00 2001 From: "jk7744.park" Date: Tue, 8 Sep 2015 22:27:39 +0900 Subject: [PATCH] tizen 2.3.1 release --- configure.ac | 56 +- debian/changelog | 348 +++ debian/rules | 3 +- ext/alsa/gstalsa.c | 7 +- ext/alsa/gstalsasrc.c | 106 +- ext/alsa/gstalsasrc.h | 5 + ext/ogg/gstoggdemux.c | 71 +- ext/ogg/gstoggstream.c | 2 +- gst-libs/gst/app/gstappsrc.c | 44 + gst-libs/gst/audio/gstaudiodecoder.c | 18 + gst-libs/gst/audio/gstbaseaudiosink.c | 3 +- gst-libs/gst/audio/gstringbuffer.c | 2 +- gst-libs/gst/interfaces/cameracontrol.c | 69 +- gst-libs/gst/interfaces/cameracontrol.h | 31 +- gst-libs/gst/interfaces/cameracontrolchannel.c | 5 +- gst-libs/gst/interfaces/cameracontrolchannel.h | 5 +- gst-libs/gst/riff/riff-media.c | 9 +- gst-libs/gst/rtsp/gstrtspconnection.c | 20 +- gst-libs/gst/rtsp/gstrtspdefs.h | 5 +- gst-libs/gst/rtsp/gstrtsptransport.c | 15 +- gst-libs/gst/tag/gstxmptag.c | 5 +- gst-libs/gst/video/video.c | 28 + gst-libs/gst/video/video.h | 30 +- gst-plugins-base-tools.manifest | 8 + gst-plugins-base.manifest | 5 + gst/audioconvert/gstaudioconvert.c | 10 +- gst/ffmpegcolorspace/gstffmpegcodecmap.c | 5 + gst/ffmpegcolorspace/gstffmpegcolorspace.c | 6 +- gst/playback/gstdecodebin2.c | 54 +- gst/playback/gstplaysink.c | 4 +- gst/subparse/Makefile.am | 6 + gst/subparse/gstsubparse.c | 326 +- gst/subparse/gstsubparse.h | 11 +- gst/subparse/samiparse.c | 1239 ++++++-- gst/subparse/samiparse.h | 10 +- gst/typefind/gsttypefindfunctions.c | 224 +- gst/videorate/gstvideorate.c | 32 +- gst/videorate/gstvideorate.h | 2 +- gst/volume/gstvolume.c | 11 +- packaging/gst-plugins-base.spec | 37 +- sys/xvimage/Makefile.am | 9 +- sys/xvimage/xv_types.h | 101 +- sys/xvimage/xvimagesink.c | 3963 +++++++++++++++++++++--- sys/xvimage/xvimagesink.h | 135 +- tools/Makefile.am | 2 +- 45 files changed, 6365 insertions(+), 722 deletions(-) mode change 100644 => 100755 ext/alsa/gstalsa.c mode change 100644 => 100755 ext/alsa/gstalsasrc.c mode change 100644 => 100755 ext/alsa/gstalsasrc.h mode change 100644 => 100755 gst-libs/gst/app/gstappsrc.c mode change 100644 => 100755 gst-libs/gst/audio/gstbaseaudiosink.c mode change 100644 => 100755 gst-libs/gst/riff/riff-media.c mode change 100644 => 100755 gst-libs/gst/rtsp/gstrtspconnection.c mode change 100644 => 100755 gst-libs/gst/rtsp/gstrtspdefs.h mode change 100644 => 100755 gst-libs/gst/video/video.h create mode 100755 gst-plugins-base-tools.manifest create mode 100755 gst-plugins-base.manifest mode change 100644 => 100755 gst/playback/gstdecodebin2.c mode change 100644 => 100755 gst/playback/gstplaysink.c mode change 100644 => 100755 gst/subparse/gstsubparse.c mode change 100644 => 100755 gst/subparse/gstsubparse.h mode change 100644 => 100755 gst/subparse/samiparse.c mode change 100644 => 100755 gst/subparse/samiparse.h mode change 100644 => 100755 gst/typefind/gsttypefindfunctions.c mode change 100644 => 100755 packaging/gst-plugins-base.spec mode change 100644 => 100755 sys/xvimage/xv_types.h mode change 100644 => 100755 sys/xvimage/xvimagesink.c mode change 100644 => 100755 sys/xvimage/xvimagesink.h diff --git a/configure.ac b/configure.ac index 1901bcf..8569474 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,14 @@ AG_GST_ARG_ENABLE_EXTERNAL AG_GST_ARG_ENABLE_EXPERIMENTAL +PKG_CHECK_MODULES(DRM, libdrm) +AC_SUBST(DRM_CFLAGS) +AC_SUBST(DRM_LIBS) + +PKG_CHECK_MODULES(DRM, libdrm-devel) +AC_SUBST(DRM_DEVEL_CFLAGS) +AC_SUBST(DRM_DEVEL_LIBS) + dnl *** checks for platform *** AG_GST_PLATFORM @@ -434,9 +442,15 @@ AG_GST_CHECK_PLUGIN(volume) dnl check for gstreamer core features (subsystems) dnl FIXME: this assumes srcdir == builddir for uninstalled setups -GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.10`"/gst/gstconfig.h" -AG_GST_PARSE_SUBSYSTEM_DISABLES($GST_CONFIGPATH) -AM_CONDITIONAL(USE_XML, test $GST_DISABLE_XML != "1") +dnl YeJin Cho : subparse needs xml for parsing smi, enalbe USE_XML +dnl GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.10`"/gst/gstconfig.h" +dnl AG_GST_PARSE_SUBSYSTEM_DISABLES($GST_CONFIGPATH) +dnl AM_CONDITIONAL(USE_XML, test $GST_DISABLE_XML != "1") + +AM_CONDITIONAL(USE_XML, true) +PKG_CHECK_MODULES(XML, libxml-2.0) +AC_SUBST(XML_CFLAGS) +AC_SUBST(XML_LIBS) dnl disable plug-ins that require libxml2's HTML support if it is not available if test "x$HAVE_LIBXML_HTML" != "xyes"; then @@ -923,6 +937,42 @@ dnl whatevertarget_LIBS and -L flags here affect the rest of the linking GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc.*' $GST_ALL_LDFLAGS" AC_SUBST(GST_PLUGIN_LDFLAGS) +dnl use xfixes +PKG_CHECK_MODULES(XFIXES, xfixes) +AC_SUBST(XFIXES_CFLAGS) +AC_SUBST(XFIXES_LIBS) + +dnl use dri2proto +PKG_CHECK_MODULES(DRI2PROTO, dri2proto) +AC_SUBST(DRI2PROTO_CFLAGS) +AC_SUBST(DRI2PROTO_LIBS) + +dnl use dri2 +PKG_CHECK_MODULES(DRI2, libdri2) +AC_SUBST(DRI2_CFLAGS) +AC_SUBST(DRI2_LIBS) + +dnl use tbm +PKG_CHECK_MODULES(TBM, libtbm) +AC_SUBST(TBM_CFLAGS) +AC_SUBST(TBM_LIBS) + +dnl Check Savs Codec Packages +#PKG_CHECK_MODULES(SAVSCODEC_HEVC, libsavscodec-neon-hevc) +#AC_SUBST(SAVSCODEC_HEVC_LDFLAGS) +#AC_SUBST(SAVSCODEC_HEVC_CFLAGS) +#AC_SUBST(SAVSCODEC_HEVC_LIBS) + +dnl use utilX +PKG_CHECK_MODULES(UTILX, utilX) +AC_SUBST(UTILX_CFLAGS) +AC_SUBST(UTILX_LIBS) + +dnl use vconf +PKG_CHECK_MODULES(VCONF, vconf) +AC_SUBST(VCONF_CFLAGS) +AC_SUBST(VCONF_LIBS) + dnl *** output files *** AC_CONFIG_FILES( diff --git a/debian/changelog b/debian/changelog index 3d1b849..925f233 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,351 @@ +gst-plugins-base0.10 (0.10.36-74) unstable; urgency=low + + * [xvimagesink] Check whether external display is connected or not when VisibilityNofify FALSE event is received + * Tag: gst-plugins-base0.10_0.10.36-74 + + -- Jeongmo Yang Sat, 01 Jun 2013 13:25:22 +0900 + +gst-plugins-base0.10 (0.10.36-73) unstable; urgency=low + + * [xvimagesink] Update window if window handle is changed and state is PAUSED + * Tag: gst-plugins-base0.10_0.10.36-73 + + -- Jeongmo Yang Thu, 30 May 2013 17:46:10 +0900 + +gst-plugins-base0.10 (0.10.36-68) unstable; urgency=low + + * [xvimagesink] Fix bug - skip putimage because of abnormal condition check code + * Tag: gst-plugins-base0.10_0.10.36-68 + + -- Jeongmo Yang Wed, 08 May 2013 13:35:56 +0900 + +gst-plugins-base0.10 (0.10.36-66) unstable; urgency=low + + * [cameracontrol] Add new field for embedded data + * Tag: gst-plugins-base0.10_0.10.36-66 + + -- Jeongmo Yang Thu, 18 Apr 2013 19:22:01 +0900 + +gst-plugins-base0.10 (0.10.36-65) unstable; urgency=low + + * [xvimagesink] Add new property for color space range + * Tag: gst-plugins-base0.10_0.10.36-65 + + -- Jeongmo Yang Thu, 18 Apr 2013 17:29:09 +0900 + +gst-plugins-base0.10 (0.10.36-64) unstable; urgency=low + + * [xvimagesink] Fix prevent issue + * Tag: gst-plugins-base0.10_0.10.36-64 + + -- Jeongmo Yang Mon, 15 Apr 2013 14:38:35 +0900 + +gst-plugins-base0.10 (0.10.36-63) unstable; urgency=low + + * [xvimagesink] Skip putimage when too many buffers are already put + * Tag: gst-plugins-base0.10_0.10.36-63 + + -- Jeongmo Yang Fri, 05 Apr 2013 20:17:24 +0900 + +gst-plugins-base0.10 (0.10.36-62) unstable; urgency=low + + * [xvimagesink] Init aligned size when change image size while playing + * Tag: gst-plugins-base0.10_0.10.36-62 + + -- Jeongmo Yang Fri, 05 Apr 2013 14:04:22 +0900 + +gst-plugins-base0.10 (0.10.36-60) unstable; urgency=low + + * [xvimagesink] Modify structure of SCMN_IMGB for compatibility + * Tag: gst-plugins-base0.10_0.10.36-60 + + -- Jeongmo Yang Fri, 22 Mar 2013 13:57:43 +0900 + +gst-plugins-base0.10 (0.10.36-59) unstable; urgency=low + + * [xvimagesink] Support new fourcc "SR32" and new buffer share method(TIZEN_BUFFER) + * Tag: gst-plugins-base0.10_0.10.36-59 + + -- Jeongmo Yang Thu, 21 Mar 2013 14:12:38 +0900 + +gst-plugins-base0.10 (0.10.36-57) unstable; urgency=low + + * [xvimagesink] Putimage with invalid gem name when receive duplicated buffer + * Tag: gst-plugins-base0.10_0.10.36-57 + + -- Jeongmo Yang Thu, 14 Feb 2013 09:54:06 +0900 + +gst-plugins-base0.10 (0.10.36-56) unstable; urgency=low + + * [xvimagesink] check if the xcontext was made when setting visible property + * Tag: gst-plugins-base0.10_0.10.36-56 + + -- Sangchul Lee Tue, 12 Feb 2013 10:01:45 +0900 + +gst-plugins-base0.10 (0.10.36-55) unstable; urgency=low + + * [xvimagesink] Enahance buffer management when DMABUF mode + * Tag: gst-plugins-base0.10_0.10.36-55 + + -- Jeongmo Yang Mon, 04 Feb 2013 18:27:02 +0900 + +gst-plugins-base0.10 (0.10.36-54) unstable; urgency=low + + * [xvimagesink] Add log at state_change function + * Tag: gst-plugins-base0.10_0.10.36-54 + + -- Jeongmo Yang Tue, 29 Jan 2013 15:04:01 +0900 + +gst-plugins-base0.10 (0.10.36-53) unstable; urgency=low + + * [xvimagesink] Fix memory leak when error or non-visible case + * Tag: gst-plugins-base0.10_0.10.36-53 + + -- Jeongmo Yang Thu, 24 Jan 2013 21:34:01 +0900 + +gst-plugins-base0.10 (0.10.36-52) unstable; urgency=low + + * [xvimagesink] Wait displaying buffer when drm close + * Tag: gst-plugins-base0.10_0.10.36-52 + + -- Jeongmo Yang Wed, 23 Jan 2013 15:26:08 +0900 + +gst-plugins-base0.10 (0.10.36-51) unstable; urgency=low + + * Update boilerplate for license + * Tag: gst-plugins-base0.10_0.10.36-51 + + -- Jeongmo Yang Sat, 19 Jan 2013 11:23:18 +0900 + +gst-plugins-base0.10 (0.10.36-49) unstable; urgency=low + + * [xvimagesink] Added "frame-render-error" signal for error caught case when calling XvPutImage() + * Tag: gst-plugins-base0.10_0.10.36-49 + + -- Sangchul Lee Fri, 18 Jan 2013 14:25:32 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+46) unstable; urgency=low + + * [xvimagesink] 1. do not store buffer information at displaying_buffers when using pixmap callback 2. change display geometry method enum type ordering + * Tag: gst-plugins-base0.10_0.10.36-1slp2+46 + + -- Sangchul Lee Tue, 02 Jan 2013 16:06:11 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+45) unstable; urgency=low + + * [xvimagesink] Fix prevent issue + * Tag: gst-plugins-base0.10_0.10.36-1slp2+45 + + -- Jeongmo Yang Mon, 31 Dec 2012 11:13:02 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+42) unstable; urgency=low + + * [xvimagesink] Fix prevent defects + * Tag: gst-plugins-base0.10_0.10.36-1slp2+42 + + -- Sangchul Lee Sat, 22 Dec 2012 15:55:23 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+41) unstable; urgency=low + + * Fix prevent issue + * Tag: gst-plugins-base0.10_0.10.36-1slp2+41 + + -- Jeongmo Yang Sat, 22 Dec 2012 14:29:44 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+38) unstable; urgency=low + + * [xvimagesink] add ORIGIN_SIZE_OR_LETTER_BOX mode for geometry method type + * Tag: gst-plugins-base0.10_0.10.36-1slp2+38 + + -- Sangchul Lee Sun, 09 Dec 2012 14:22:43 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+37) unstable; urgency=low + + * [xvimagesink] fix bug - refer im_format in xvimage(not in xvimagesink handle) created by _buffer_alloc() + * Tag: gst-plugins-base0.10_0.10.36-1slp2+37 + + -- Sangchul Lee Sat, 08 Dec 2012 19:14:17 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+36) unstable; urgency=low + + * [xvimagesink] add defensive code not to unref finalized buffer + * Tag: gst-plugins-base0.10_0.10.36-1slp2+36 + + -- Jeongmo Yang Thu, 06 Dec 2012 20:07:48 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+35) unstable; urgency=low + + * [xvimagesink] move g_mutex_lock(flow_lock) code caused of unlock many times + * Tag: gst-plugins-base0.10_0.10.36-1slp2+35 + + -- Sangchul Lee Wed, 05 Dec 2012 13:54:11 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+33) unstable; urgency=low + + * [xvimagesink] Improve buffer management when DMABUF mode + * Tag: gst-plugins-base0.10_0.10.36-1slp2+33 + + -- Jeongmo Yang Tue, 04 Dec 2012 15:26:38 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+31) unstable; urgency=low + + * [xvimagesink] do drm_fini() when GST_STATE_CHANGE_PAUSED_TO_READY + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+31 + + -- Sangchul Lee Wed, 28 Nov 2012 20:50:12 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+30) unstable; urgency=low + + * [xvimagesink] add code for posting "prepare-xid" element message with video size and display size on the bus to give applications an opportunity to set xwindow or xpixmap + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+30 + + -- Sangchul Lee Fri, 16 Nov 2012 13:36:23 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+29) unstable; urgency=low + + * [xvimagesink] Support SN21 format + * Tag: gst-plugins-base0.10_0.10.36-1slp2+29 + + -- Jeongmo Yang Wed, 14 Nov 2012 21:02:56 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+28) unstable; urgency=low + + * [xvimagesink] add flow_lock/unlock in _show_frame() preparing in the event of using _set_window_handle() + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+28 + + -- Sangchul Lee Wed, 14 Nov 2012 10:34:56 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+27) unstable; urgency=low + + * [typefind] Modify aac type find to select correctly + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+27 + + -- Sunghyun Eum Wed, 07 Nov 2012 21:11:36 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+26) unstable; urgency=low + + * [xvimagesink] fix bug - first incoming pixmap's drawing region was set 0 when using multiple pixmaps + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+26 + + -- Sangchul Lee Wed, 07 Nov 2012 17:08:56 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+25) unstable; urgency=low + + * [xvimagesink] Improve code for dmabuf mode - close gem handle after putimage + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+25 + + -- Jeongmo Yang Tue, 06 Nov 2012 18:06:19 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+22) unstable; urgency=low + + * [xvimagesink] Add new property "flip" + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+22 + + -- Jeongmo Yang Mon, 29 Oct 2012 16:32:17 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+21) unstable; urgency=low + + * [xvimagesink] support multiple pixmaps usage + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+21 + + -- Sangchul Lee Fri, 26 Oct 2012 16:38:56 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+20) unstable; urgency=low + + * [xvimagesink] fix resources leak in drm_init() + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+20 + + -- Sangchul Lee Thu, 25 Oct 2012 15:48:53 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+19) unstable; urgency=low + + * [xvimagesink] remove code for closing fd + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+19 + + -- Sangchul Lee Thu, 25 Oct 2012 00:22:49 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+18) unstable; urgency=low + + * [subparse] fix for suaparse to enable smi + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+18 + + -- Yejin Cho Mon, 22 Oct 2012 15:23:54 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+17) unstable; urgency=low + + * [ffmpegcolorspace] Support ITLV(actucally UYVY) fourcc + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+17 + + -- Jeongmo Yang Fri, 12 Oct 2012 10:47:00 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+16) unstable; urgency=low + + * [xvimagesink] Fix leak for DRM device open and close + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+16 + + -- Jeongmo Yang Thu, 11 Oct 2012 13:17:30 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+13) unstable; urgency=low + + * [xvimagesink] Update code for checking window event + * Git: gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+13 + + -- Jeongmo Yang Thu, 27 Sep 2012 14:10:20 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+12) unstable; urgency=low + + * [xvimagesink] Apply dmabuf feature + * Git: framework/multimedia/gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+12 + + -- Jeongmo Yang Thu, 20 Sep 2012 17:29:24 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+11) unstable; urgency=low + + * Add manifest file + * Git: framework/multimedia/gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+11 + + -- Jeongmo Yang Thu, 20 Sep 2012 14:29:27 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+10) unstable; urgency=low + + * Add extended profile to support 3g2 file + * Git: framework/multimedia/gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+10 + + -- Sunghyun Eum Wed, 19 Sep 2012 10:09:38 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+8) unstable; urgency=low + + * Add specific fourcc to gst_video_format_parse_caps for proper checking + * Git: framework/multimedia/gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+8 + + -- Sunghyun Eum Tue, 11 Sep 2012 09:10:29 +0900 + +gst-plugins-base0.10 (0.10.36-1slp2+7) unstable; urgency=low + + * Modified TCP data handling for WFD specific case + * Git: slp/pkgs/g/gst-plugins-base0.10 + * Tag: gst-plugins-base0.10_0.10.36-1slp2+7 + + -- Santhoshi KS Tue, 28 Aug 2012 19:46:30 +0900 + gst-plugins-base0.10 (0.10.36-1slp2+6) unstable; urgency=low * Destroy xim_transparenter image when destroying xwindow diff --git a/debian/rules b/debian/rules index 25fc4fb..9ad8294 100755 --- a/debian/rules +++ b/debian/rules @@ -30,7 +30,8 @@ CONFIGURE_OPTION +=--prefix=/usr \ CFLAGS += -Wall -g -fPIC \ -DGST_EXT_XV_ENHANCEMENT \ -DGST_EXT_LINK_FIMCCONVERT \ - -DGST_EXT_MIME_TYPES + -DGST_EXT_MIME_TYPES \ + -DGST_EXT_ENABLE_SMI ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c old mode 100644 new mode 100755 index 94ed44c..dcb52e7 --- a/ext/alsa/gstalsa.c +++ b/ext/alsa/gstalsa.c @@ -121,8 +121,11 @@ gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params, s = gst_caps_get_structure (in_caps, i); if (!gst_structure_has_name (s, "audio/x-raw-int")) { - GST_WARNING_OBJECT (obj, "skipping non-int format"); - continue; + GST_WARNING_OBJECT (obj, "checking for LPCM format"); + if(!gst_structure_has_name (s, "audio/x-lpcm")) { + GST_WARNING_OBJECT (obj, "skipping non-int format"); + continue; + } } if (!gst_structure_get_int (s, "width", &width) || !gst_structure_get_int (s, "depth", &depth)) diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c old mode 100644 new mode 100755 index 917f0dc..ce875aa --- a/ext/alsa/gstalsasrc.c +++ b/ext/alsa/gstalsasrc.c @@ -62,6 +62,7 @@ enum PROP_DEVICE, PROP_DEVICE_NAME, PROP_CARD_NAME, + PROP_IS_LIVE, PROP_LAST }; @@ -88,6 +89,7 @@ static gboolean gst_alsasrc_close (GstAudioSrc * asrc); static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length); static guint gst_alsasrc_delay (GstAudioSrc * asrc); static void gst_alsasrc_reset (GstAudioSrc * asrc); +static GstStateChangeReturn gst_alsasrc_change_state (GstElement * element, GstStateChange transition); /* AlsaSrc signals and args */ enum @@ -105,7 +107,13 @@ static GstStaticPadTemplate alsasrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " + GST_STATIC_CAPS ("audio/x-lpcm, " + "endianness = (int) { 1234, 4321 }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];" + "audio/x-raw-int, " "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " "signed = (boolean) { TRUE, FALSE }, " "width = (int) 32, " @@ -202,8 +210,10 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass) GObjectClass *gobject_class; GstBaseSrcClass *gstbasesrc_class; GstAudioSrcClass *gstaudiosrc_class; + GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; gstbasesrc_class = (GstBaseSrcClass *) klass; gstaudiosrc_class = (GstAudioSrcClass *) klass; @@ -220,6 +230,7 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass) gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_alsasrc_read); gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_alsasrc_delay); gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_alsasrc_reset); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_alsasrc_change_state); g_object_class_install_property (gobject_class, PROP_DEVICE, g_param_spec_string ("device", "Device", @@ -235,6 +246,86 @@ gst_alsasrc_class_init (GstAlsaSrcClass * klass) g_param_spec_string ("card-name", "Card name", "Human-readable name of the sound card", DEFAULT_PROP_CARD_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_IS_LIVE, + g_param_spec_boolean ("is-live", + "is live session", + "is live session", + 0, G_PARAM_READWRITE)); +} + +static gboolean timer_flush_data(GstAlsaSrc *src) +{ + if(src->handle_pause) { + gint32 frames = 0; + gint err; + frames = snd_pcm_avail(src->handle); + if(frames>0) { + GST_DEBUG("Frames avail for reading: %d", frames); + err = snd_pcm_forward(src->handle,frames); + if (err < 0) + GST_WARNING("Can't recovery from suspend, prepare failed: %s", snd_strerror (err)); + } + return TRUE; + } + return FALSE; +} + +static GstStateChangeReturn +gst_alsasrc_change_state (GstElement * element, GstStateChange transition) +{ + GstAlsaSrc *src = GST_ALSA_SRC (element); + + GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_INFO("GST_STATE_CHANGE_NULL_TO_READY"); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_INFO("GST_STATE_CHANGE_READY_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_INFO("GST_STATE_CHANGE_PAUSED_TO_PLAYING"); + if(src->is_live) { + GstAudioSrc * asrc = (GstAudioSrc*)src; + gint err; + GST_ALSA_SRC_LOCK (asrc); + + gint32 frames = 0; + frames = snd_pcm_avail(src->handle); + if(frames>0) { + GST_DEBUG("Frames avail for reading: %d", frames); + err = snd_pcm_forward(src->handle,frames); + if (err < 0) + GST_WARNING("Can't recovery from suspend, prepare failed: %s", snd_strerror (err)); + } + GST_ALSA_SRC_UNLOCK (asrc); + src->handle_pause = FALSE; + g_cond_signal(src->pause_cond); + } + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_INFO("GST_STATE_CHANGE_PLAYING_TO_PAUSED"); + if(src->is_live) { + src->handle_pause = TRUE; + src->flush_src_id = g_timeout_add(100, timer_flush_data, src); + } + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_INFO("GST_STATE_CHANGE_PAUSED_TO_READY"); + if (src->is_live) { + if (src->flush_src_id > 0) g_source_remove(src->flush_src_id); + src->handle_pause = FALSE; + } + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_INFO("GST_STATE_CHANGE_READY_TO_NULL"); + break; + default : + break; + } + result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + return result; } static void @@ -253,6 +344,10 @@ gst_alsasrc_set_property (GObject * object, guint prop_id, src->device = g_strdup (DEFAULT_PROP_DEVICE); } break; + case PROP_IS_LIVE: + src->is_live = g_value_get_boolean (value); + GST_DEBUG("is_live %d", src->is_live); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -281,6 +376,9 @@ gst_alsasrc_get_property (GObject * object, guint prop_id, gst_alsa_find_card_name (GST_OBJECT_CAST (src), src->device, SND_PCM_STREAM_CAPTURE)); break; + case PROP_IS_LIVE: + g_value_set_boolean (value, src->is_live); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -296,6 +394,9 @@ gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class) alsasrc->cached_caps = NULL; alsasrc->alsa_lock = g_mutex_new (); + alsasrc->pause_cond = g_cond_new (); + alsasrc->pause_lock = g_mutex_new (); + alsasrc->handle_pause = FALSE; } #define CHECK(call, error) \ @@ -745,6 +846,7 @@ xrun_recovery (GstAlsaSrc * alsa, snd_pcm_t * handle, gint err) GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err); if (err == -EPIPE) { /* under-run */ + GST_DEBUG_OBJECT (alsa, "overrun case"); err = snd_pcm_prepare (handle); if (err < 0) GST_WARNING_OBJECT (alsa, @@ -780,6 +882,8 @@ gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length) cptr = length / alsa->bytes_per_sample; ptr = data; + if(alsa->is_live && alsa->handle_pause) g_cond_wait(alsa->pause_cond, alsa->pause_lock); + GST_ALSA_SRC_LOCK (asrc); while (cptr > 0) { if ((err = snd_pcm_readi (alsa->handle, ptr, cptr)) < 0) { diff --git a/ext/alsa/gstalsasrc.h b/ext/alsa/gstalsasrc.h old mode 100644 new mode 100755 index d0fcbf0..6a92bae --- a/ext/alsa/gstalsasrc.h +++ b/ext/alsa/gstalsasrc.h @@ -69,10 +69,15 @@ struct _GstAlsaSrc { guint period_time; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; + gboolean is_live; + guint flush_src_id; GstAlsaMixer *mixer; GMutex *alsa_lock; + gboolean handle_pause; + GCond *pause_cond; + GMutex *pause_lock; }; struct _GstAlsaSrcClass { diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index ac01b05..102e16d 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -796,7 +796,7 @@ gst_ogg_demux_collect_sync_time (GstOggDemux * ogg, GstOggChain * chain) /* submit a packet to the oggpad, this function will run the * typefind code for the pad if this is the first packet for this - * stream + * stream */ static GstFlowReturn gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) @@ -1049,7 +1049,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) return ret; } -/* flush at most @npackets from the stream layer. All packets if +/* flush at most @npackets from the stream layer. All packets if * @npackets is 0; */ static GstFlowReturn @@ -2337,7 +2337,7 @@ boundary_reached: } /* from the current offset, find the previous page, seeking backwards - * until we find the page. + * until we find the page. */ static GstFlowReturn gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset) @@ -2440,7 +2440,7 @@ gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg) pad->added = FALSE; } - /* if we cannot seek back to the chain, we can destroy the chain + /* if we cannot seek back to the chain, we can destroy the chain * completely */ if (!ogg->pullmode) { gst_ogg_chain_free (chain); @@ -2617,7 +2617,7 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain, static gboolean do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin, gint64 end, gint64 begintime, gint64 endtime, gint64 target, - gint64 * offset) + gint64 * offset, gboolean only_serial_no, gint serialno) { gint64 best; GstFlowReturn ret; @@ -2691,6 +2691,11 @@ do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin, continue; } + /* Avoid seeking to an incorrect granuletime by only considering + the stream for which we found the earliest time */ + if (only_serial_no && ogg_page_serialno (&og) != serialno) + continue; + /* get the stream */ pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og)); if (pad == NULL || pad->map.is_skeleton) @@ -2808,8 +2813,8 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, gint64 total; gint64 result = 0; GstFlowReturn ret; - gint i, pending, len; - gboolean first_parsed_page = TRUE; + gint i, pending; + gint serialno = 0; position = segment->last_stop; @@ -2833,14 +2838,14 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, target = position - total + begintime; if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target, - &best)) + &best, FALSE, 0)) goto seek_error; /* second step: find pages for all streams, we use the keyframe_granule to keep * track of which ones we saw. If we have seen a page for each stream we can * calculate the positions of each keyframe. */ GST_DEBUG_OBJECT (ogg, "find keyframes"); - len = pending = chain->streams->len; + pending = chain->streams->len; /* figure out where the keyframes are */ keytarget = target; @@ -2874,32 +2879,6 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, continue; } - /* we only do this the first time we pass here */ - if (first_parsed_page) { - /* Now that we have a time reference from the page, we can check - * whether all streams still have pages from here on. - * - * This would be more elegant before the loop, but getting the page from - * there without breaking anything would be more costly */ - granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map, - granulepos); - for (i = 0; i < len; i++) { - GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i); - - if (stream == pad) - /* we already know we have at least one page (the current one) - * for this stream */ - continue; - - if (granule_time > stream->map.total_time) - /* we won't encounter any more pages of this stream, so we don't - * try finding a key frame for it */ - pending--; - } - first_parsed_page = FALSE; - } - - /* in reverse we want to go past the page with the lower timestamp */ if (segment->rate < 0.0) { /* get time for this pad */ @@ -2934,8 +2913,10 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, /* collect smallest value */ if (keyframe_time != -1) { keyframe_time += begintime; - if (keyframe_time < keytarget) + if (keyframe_time < keytarget) { + serialno = pad->map.serialno; keytarget = keyframe_time; + } } next: @@ -2954,7 +2935,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, /* last step, seek to the location of the keyframe */ if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, - keytarget, &best)) + keytarget, &best, TRUE, serialno)) goto seek_error; } else { /* seek back to previous position */ @@ -3208,7 +3189,7 @@ gst_ogg_demux_perform_seek_pull (GstOggDemux * ogg, GstEvent * event) ogg->segment_running = TRUE; ogg->seqnum = seqnum; - /* restart our task since it might have been stopped when we did the + /* restart our task since it might have been stopped when we did the * flush. */ gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop, ogg->sinkpad); @@ -3245,8 +3226,12 @@ gst_ogg_demux_get_duration_push (GstOggDemux * ogg, int flags) granpos there, but it's fairly likely */ position = ogg->push_byte_length - DURATION_CHUNK_OFFSET - EOS_AVOIDANCE_THRESHOLD; - if (position < 0) - position = 0; + if (position < 0) { + if (ogg->push_byte_length > EOS_AVOIDANCE_THRESHOLD) + position = ogg->push_byte_length - (EOS_AVOIDANCE_THRESHOLD / 2); + else + position = 0; + } GST_DEBUG_OBJECT (ogg, "Getting duration, seeking near the end, to %" G_GINT64_FORMAT, position); @@ -3578,9 +3563,9 @@ done: } /* read a chain from the ogg file. This code will - * read all BOS pages and will create and return a GstOggChain - * structure with the results. - * + * read all BOS pages and will create and return a GstOggChain + * structure with the results. + * * This function will also read N pages from each stream in the * chain and submit them to the decoders. When the decoder has * decoded the first buffer, we know the timestamp of the first diff --git a/ext/ogg/gstoggstream.c b/ext/ogg/gstoggstream.c index 3b267fa..5fa0eb9 100644 --- a/ext/ogg/gstoggstream.c +++ b/ext/ogg/gstoggstream.c @@ -797,7 +797,7 @@ setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet) static gboolean is_header_vorbis (GstOggStream * pad, ogg_packet * packet) { - if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0) + if (packet->bytes == 0 || (packet->packet[0] & 0x01) == 0) return FALSE; if (packet->packet[0] == 5) { diff --git a/gst-libs/gst/app/gstappsrc.c b/gst-libs/gst/app/gstappsrc.c old mode 100644 new mode 100755 index 24686b9..58039d1 --- a/gst-libs/gst/app/gstappsrc.c +++ b/gst-libs/gst/app/gstappsrc.c @@ -234,6 +234,7 @@ static gboolean gst_app_src_query (GstBaseSrc * src, GstQuery * query); static GstFlowReturn gst_app_src_push_buffer_action (GstAppSrc * appsrc, GstBuffer * buffer); +static gboolean gst_app_src_send_event (GstElement * element, GstEvent * event); static guint gst_app_src_signals[LAST_SIGNAL] = { 0 }; @@ -272,12 +273,14 @@ gst_app_src_class_init (GstAppSrcClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass; + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);; gobject_class->dispose = gst_app_src_dispose; gobject_class->finalize = gst_app_src_finalize; gobject_class->set_property = gst_app_src_set_property; gobject_class->get_property = gst_app_src_get_property; + gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_app_src_send_event); /** * GstAppSrc::caps @@ -1637,6 +1640,47 @@ gst_app_src_set_callbacks (GstAppSrc * appsrc, GST_OBJECT_UNLOCK (appsrc); } +static gboolean +gst_app_src_send_event (GstElement * element, GstEvent * event) +{ + GstAppSrc *appsrc; + gboolean result = FALSE; + GstBaseSrc *src; + + src = GST_BASE_SRC (element); + appsrc = GST_APP_SRC (element); + GstAppSrcPrivate *priv = appsrc->priv; + + GST_DEBUG_OBJECT (appsrc, "handling event %p %" GST_PTR_FORMAT, event, event); + + switch (GST_EVENT_TYPE (event)) { + /* bidirectional events */ + case GST_EVENT_FLUSH_STOP: + g_mutex_lock (priv->mutex); + GST_INFO_OBJECT (appsrc, "flushing internal queue"); + gst_app_src_flush_queued (appsrc); + priv->flushing = FALSE; + g_mutex_unlock (priv->mutex); + result = gst_pad_push_event (src ->srcpad, event); + break; + /* fallback */ + case GST_EVENT_FLUSH_START: + g_mutex_lock (priv->mutex); + priv->flushing = TRUE; + g_mutex_unlock (priv->mutex); + result = gst_pad_push_event (src ->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + result = gst_pad_push_event (src ->srcpad, event); + break; + default: + result = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); + break; + } + + return result; +} + /*** GSTURIHANDLER INTERFACE *************************************************/ static GstURIType diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index e35779e..e258d44 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -220,6 +220,9 @@ struct _GstAudioDecoderPrivate GstAdapter *adapter; /* tracking input ts for changes */ GstClockTime prev_ts; +#if 1 + guint64 prev_distance; +#endif /* frames obtained from input */ GQueue frames; /* collected output data */ @@ -444,6 +447,9 @@ gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full) dec->priv->out_ts = GST_CLOCK_TIME_NONE; dec->priv->out_dur = 0; dec->priv->prev_ts = GST_CLOCK_TIME_NONE; +#if 1 + dec->priv->prev_distance = 0; +#endif dec->priv->drained = TRUE; dec->priv->base_ts = GST_CLOCK_TIME_NONE; dec->priv->samples = 0; @@ -976,6 +982,7 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force) if (G_LIKELY (av)) { gint len; GstClockTime ts; + guint64 distance; /* parse if needed */ if (klass->parse) { @@ -1015,6 +1022,7 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force) len = av; } /* track upstream ts, but do not get stuck if nothing new upstream */ +#if 0 ts = gst_adapter_prev_timestamp (priv->adapter, NULL); if (ts == priv->prev_ts) { GST_LOG_OBJECT (dec, "ts == prev_ts; discarding"); @@ -1022,6 +1030,16 @@ gst_audio_decoder_push_buffers (GstAudioDecoder * dec, gboolean force) } else { priv->prev_ts = ts; } +#else + ts = gst_adapter_prev_timestamp (priv->adapter, &distance); + if (ts != priv->prev_ts || distance <= priv->prev_distance) { + priv->prev_ts = ts; + priv->prev_distance = distance; + } else { + GST_LOG_OBJECT (dec, "ts == prev_ts; discarding"); + ts = GST_CLOCK_TIME_NONE; + } +#endif buffer = gst_adapter_take_buffer (priv->adapter, len); buffer = gst_buffer_make_metadata_writable (buffer); GST_BUFFER_TIMESTAMP (buffer) = ts; diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c old mode 100644 new mode 100755 index e7ff30d..0dd84c9 --- a/gst-libs/gst/audio/gstbaseaudiosink.c +++ b/gst-libs/gst/audio/gstbaseaudiosink.c @@ -1438,7 +1438,8 @@ gst_base_audio_sink_sync_latency (GstBaseSink * bsink, GstMiniObject * obj) } /* start ringbuffer so we can start slaving right away when we need to */ - gst_ring_buffer_start (sink->ringbuffer); + if (sink->priv->slave_method != GST_BASE_AUDIO_SINK_SLAVE_NONE) + gst_ring_buffer_start (sink->ringbuffer); GST_DEBUG_OBJECT (sink, "internal time: %" GST_TIME_FORMAT " external time: %" GST_TIME_FORMAT, diff --git a/gst-libs/gst/audio/gstringbuffer.c b/gst-libs/gst/audio/gstringbuffer.c index 5069304..385d7b7 100644 --- a/gst-libs/gst/audio/gstringbuffer.c +++ b/gst-libs/gst/audio/gstringbuffer.c @@ -329,7 +329,7 @@ gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps) /* we have to differentiate between int and float formats */ mimetype = gst_structure_get_name (structure); - if (g_str_equal (mimetype, "audio/x-raw-int")) { + if (g_str_equal (mimetype, "audio/x-raw-int") || g_str_equal (mimetype, "audio/x-lpcm")) { gint endianness; const FormatDef *def; gint j, bytes; diff --git a/gst-libs/gst/interfaces/cameracontrol.c b/gst-libs/gst/interfaces/cameracontrol.c index 73ba697..60d77a8 100644 --- a/gst-libs/gst/interfaces/cameracontrol.c +++ b/gst-libs/gst/interfaces/cameracontrol.c @@ -1,7 +1,7 @@ /* * GStreamer Camera Control Interface * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. * * Contact: Jeongmo Yang * @@ -132,8 +132,13 @@ static void gst_camera_control_class_init(GstCameraControlClass *klass) klass->get_part_color = NULL; klass->get_exif_info = NULL; klass->set_capture_command = NULL; + klass->set_record_command = NULL; klass->start_face_zoom = NULL; klass->stop_face_zoom = NULL; + klass->set_ae_lock = NULL; + klass->get_ae_lock = NULL; + klass->set_awb_lock = NULL; + klass->get_awb_lock = NULL; } const GList* gst_camera_control_list_channels(GstCameraControl *control) @@ -148,23 +153,23 @@ const GList* gst_camera_control_list_channels(GstCameraControl *control) } -gboolean gst_camera_control_set_value(GstCameraControl *control, GstCameraControlChannel *control_channel) +gboolean gst_camera_control_set_value(GstCameraControl *control, GstCameraControlChannel *control_channel, gint value) { GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); if (klass->set_value) { - return klass->set_value(control, control_channel); + return klass->set_value(control, control_channel, value); } return FALSE; } -gboolean gst_camera_control_get_value(GstCameraControl *control, GstCameraControlChannel *control_channel) +gboolean gst_camera_control_get_value(GstCameraControl *control, GstCameraControlChannel *control_channel, gint *value) { GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); if (klass->get_value) { - return klass->get_value(control, control_channel); + return klass->get_value(control, control_channel, value); } return FALSE; @@ -493,6 +498,16 @@ void gst_camera_control_set_capture_command(GstCameraControl *control, GstCamera return; } +void gst_camera_control_set_record_command(GstCameraControl *control, GstCameraControlRecordCommand cmd) +{ + GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); + + if (klass->set_record_command) { + klass->set_record_command(control, cmd); + } + + return; +} gboolean gst_camera_control_start_face_zoom(GstCameraControl *control, gint x, gint y, gint zoom_level) { @@ -516,6 +531,50 @@ gboolean gst_camera_control_stop_face_zoom(GstCameraControl *control) return FALSE; } +gboolean gst_camera_control_set_ae_lock(GstCameraControl *control, gboolean lock) +{ + GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); + + if (klass->set_ae_lock) { + return klass->set_ae_lock(control, lock); + } + + return FALSE; +} + +gboolean gst_camera_control_get_ae_lock(GstCameraControl *control, gboolean *lock) +{ + GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); + + if (klass->get_ae_lock) { + return klass->get_ae_lock(control, lock); + } + + return FALSE; +} + +gboolean gst_camera_control_set_awb_lock(GstCameraControl *control, gboolean lock) +{ + GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); + + if (klass->set_awb_lock) { + return klass->set_awb_lock(control, lock); + } + + return FALSE; +} + +gboolean gst_camera_control_get_awb_lock(GstCameraControl *control, gboolean *lock) +{ + GstCameraControlClass *klass = GST_CAMERA_CONTROL_GET_CLASS(control); + + if (klass->get_awb_lock) { + return klass->get_awb_lock(control, lock); + } + + return FALSE; +} + void gst_camera_control_value_changed(GstCameraControl *control, GstCameraControlChannel *control_channel, gint value) { g_signal_emit(G_OBJECT(control), gst_camera_control_signals[CONTROL_VALUE_CHANGED], 0, control_channel, value); diff --git a/gst-libs/gst/interfaces/cameracontrol.h b/gst-libs/gst/interfaces/cameracontrol.h index f5ec544..d4780c4 100644 --- a/gst-libs/gst/interfaces/cameracontrol.h +++ b/gst-libs/gst/interfaces/cameracontrol.h @@ -1,7 +1,7 @@ /* * GStreamer Camera Control Interface * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. * * Contact: Jeongmo Yang * @@ -154,7 +154,15 @@ typedef enum GST_CAMERA_CONTROL_CAPTURE_COMMAND_STOP_MULTISHOT, } GstCameraControlCaptureCommand; - +/** + * Enumerations for Camera record command. + */ +typedef enum +{ + GST_CAMERA_CONTROL_RECORD_COMMAND_NONE, + GST_CAMERA_CONTROL_RECORD_COMMAND_START, + GST_CAMERA_CONTROL_RECORD_COMMAND_STOP, +} GstCameraControlRecordCommand; ///////////////////////////////// // For Query functionalities // @@ -356,6 +364,7 @@ typedef struct _GstCameraControlExifInfo { gint exif_image_height; gint exposure_bias_in_APEX; /* Exposure bias in APEX standard */ gint software_used; /* Firmware S/W version */ + unsigned char *p_embedded_data; /* Pointer for embedded data */ /* Fixed value */ gint component_configuration; /* color components arrangement */ @@ -376,8 +385,8 @@ typedef struct _GstCameraControlClass { /* virtual functions */ const GList*(*list_channels) (GstCameraControl *control); - gboolean (*set_value) (GstCameraControl *control, GstCameraControlChannel *control_channel); - gboolean (*get_value) (GstCameraControl *control, GstCameraControlChannel *control_channel); + gboolean (*set_value) (GstCameraControl *control, GstCameraControlChannel *control_channel, gint value); + gboolean (*get_value) (GstCameraControl *control, GstCameraControlChannel *control_channel, gint *value); gboolean (*set_exposure) (GstCameraControl *control, gint type, gint value1, gint value2); gboolean (*get_exposure) (GstCameraControl *control, gint type, gint *value1, gint *value2); gboolean (*set_capture_mode) (GstCameraControl *control, gint type, gint value); @@ -407,8 +416,13 @@ typedef struct _GstCameraControlClass { gboolean (*get_misc_dev_info) (GstCameraControl *control, gint dev_id, GstCameraControlCtrlListInfoType *info); gboolean (*get_extra_dev_info) (GstCameraControl *control, gint dev_id, GstCameraControlExtraInfoType *info); void (*set_capture_command) (GstCameraControl *control, GstCameraControlCaptureCommand cmd); + void (*set_record_command) (GstCameraControl *control, GstCameraControlRecordCommand cmd); gboolean (*start_face_zoom) (GstCameraControl *control, gint x, gint y, gint zoom_level); gboolean (*stop_face_zoom) (GstCameraControl *control); + gboolean (*set_ae_lock) (GstCameraControl *control, gboolean lock); + gboolean (*get_ae_lock) (GstCameraControl *control, gboolean *lock); + gboolean (*set_awb_lock) (GstCameraControl *control, gboolean lock); + gboolean (*get_awb_lock) (GstCameraControl *control, gboolean *lock); /* signals */ void (* value_changed) (GstCameraControl *control, GstCameraControlChannel *channel, gint value); @@ -419,8 +433,8 @@ GType gst_camera_control_get_type(void); /* virtual class function wrappers */ const GList* gst_camera_control_list_channels (GstCameraControl *control); -gboolean gst_camera_control_set_value (GstCameraControl *control, GstCameraControlChannel *control_channel); -gboolean gst_camera_control_get_value (GstCameraControl *control, GstCameraControlChannel *control_channel); +gboolean gst_camera_control_set_value (GstCameraControl *control, GstCameraControlChannel *control_channel, gint value); +gboolean gst_camera_control_get_value (GstCameraControl *control, GstCameraControlChannel *control_channel, gint *value); gboolean gst_camera_control_set_exposure (GstCameraControl *control, gint type, gint value1, gint value2); gboolean gst_camera_control_get_exposure (GstCameraControl *control, gint type, gint *value1, gint *value2); gboolean gst_camera_control_set_capture_mode (GstCameraControl *control, gint type, gint value); @@ -450,8 +464,13 @@ gboolean gst_camera_control_get_basic_dev_info (GstCameraControl *control, gin gboolean gst_camera_control_get_misc_dev_info (GstCameraControl *control, gint dev_id, GstCameraControlCtrlListInfoType *info); gboolean gst_camera_control_get_extra_dev_info (GstCameraControl *control, gint dev_id, GstCameraControlExtraInfoType *info); void gst_camera_control_set_capture_command (GstCameraControl *control, GstCameraControlCaptureCommand cmd); +void gst_camera_control_set_record_command (GstCameraControl *control, GstCameraControlRecordCommand cmd); gboolean gst_camera_control_start_face_zoom (GstCameraControl *control, gint x, gint y, gint zoom_level); gboolean gst_camera_control_stop_face_zoom (GstCameraControl *control); +gboolean gst_camera_control_set_ae_lock (GstCameraControl *control, gboolean lock); +gboolean gst_camera_control_get_ae_lock (GstCameraControl *control, gboolean *lock); +gboolean gst_camera_control_set_awb_lock (GstCameraControl *control, gboolean lock); +gboolean gst_camera_control_get_awb_lock (GstCameraControl *control, gboolean *lock); /* trigger signal */ diff --git a/gst-libs/gst/interfaces/cameracontrolchannel.c b/gst-libs/gst/interfaces/cameracontrolchannel.c index 415210e..86c7ce9 100644 --- a/gst-libs/gst/interfaces/cameracontrolchannel.c +++ b/gst-libs/gst/interfaces/cameracontrolchannel.c @@ -1,5 +1,8 @@ /* GStreamer Camera Control Channel Interface - * Copyright (C) 2003 Ronald Bultje + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. + * + * Contact: Jeongmo Yang * * cameracontrolchannel.c: cameracontrol channel object design * diff --git a/gst-libs/gst/interfaces/cameracontrolchannel.h b/gst-libs/gst/interfaces/cameracontrolchannel.h index 417debd..d8a2979 100644 --- a/gst-libs/gst/interfaces/cameracontrolchannel.h +++ b/gst-libs/gst/interfaces/cameracontrolchannel.h @@ -1,5 +1,8 @@ /* GStreamer Camera Control Channel Interface - * Copyright (C) 2003 Ronald Bultje + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. + * + * Contact: Jeongmo Yang * * cameracontrolchannel.h: individual channel object * diff --git a/gst-libs/gst/riff/riff-media.c b/gst-libs/gst/riff/riff-media.c old mode 100644 new mode 100755 index bc7ac84..a862e94 --- a/gst-libs/gst/riff/riff-media.c +++ b/gst-libs/gst/riff/riff-media.c @@ -60,7 +60,7 @@ gst_riff_create_video_caps (guint32 codec_fcc, switch (codec_fcc) { case GST_MAKE_FOURCC ('D', 'I', 'B', ' '): /* uncompressed RGB */ - case GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00): + //case GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00): /*Commented so that FOURCC 0000 doesn't get detected as RGB format. ALso no standard for FOURCC 0000 */ case GST_MAKE_FOURCC ('R', 'G', 'B', ' '): case GST_MAKE_FOURCC ('R', 'A', 'W', ' '): { @@ -1396,7 +1396,12 @@ gst_riff_create_audio_caps (guint16 codec_id, { gint version = (codec_id - GST_RIFF_WAVE_FORMAT_WMAV1) + 1; - channels_max = 6; + /*Since gstreamer already knows GST_RIFF_WAVE_FORMAT_WMAV3_L (WMA lossless media) as version 3.*/ + if(codec_id == GST_RIFF_WAVE_FORMAT_WMAV3_L) + version = (codec_id - GST_RIFF_WAVE_FORMAT_WMAV1); + + /* WMA Pro supports upto 8 channels */ + channels_max = 8; block_align = TRUE; caps = gst_caps_new_simple ("audio/x-wma", diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c b/gst-libs/gst/rtsp/gstrtspconnection.c old mode 100644 new mode 100755 index 731add3..bf721d5 --- a/gst-libs/gst/rtsp/gstrtspconnection.c +++ b/gst-libs/gst/rtsp/gstrtspconnection.c @@ -1409,9 +1409,9 @@ message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message) case GST_RTSP_MESSAGE_REQUEST: /* create request string, add CSeq */ g_string_append_printf (str, "%s %s RTSP/1.0\r\n" - "CSeq: %d\r\n", - gst_rtsp_method_as_text (message->type_data.request.method), - message->type_data.request.uri, conn->cseq++); + "CSeq: %d\r\n", + gst_rtsp_method_as_text (message->type_data.request.method), + message->type_data.request.uri, conn->cseq++); /* add session id if we have one */ if (conn->session_id[0] != '\0') { gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1); @@ -1443,8 +1443,19 @@ message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message) break; case GST_RTSP_MESSAGE_DATA: { - guint8 data_header[4]; +#ifdef SAMSUNG_WFD_SPEC + /* This change is made because WFD Sink does not understand the first 2 + * bytes i.e (magic number and channel) of TCP Interleaved data. This + * is done specifically to support WFD Sink's limitation */ + guint8 data_header[2]; + data_header[0] = (message->body_size >> 8) & 0xff; + data_header[1] = message->body_size & 0xff; + + /* create string with header and data */ + str = g_string_append_len (str, (gchar *) data_header, 2); +#else + guint8 data_header[4]; /* prepare data header */ data_header[0] = '$'; data_header[1] = message->type_data.data.channel; @@ -1453,6 +1464,7 @@ message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message) /* create string with header and data */ str = g_string_append_len (str, (gchar *) data_header, 4); +#endif str = g_string_append_len (str, (gchar *) message->body, message->body_size); diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h old mode 100644 new mode 100755 index 3727bf2..32bc3ee --- a/gst-libs/gst/rtsp/gstrtspdefs.h +++ b/gst-libs/gst/rtsp/gstrtspdefs.h @@ -81,6 +81,7 @@ G_STMT_START { \ * @GST_RTSP_ETIMEOUT: a timeout occured * @GST_RTSP_ETGET: the tunnel GET request has been performed * @GST_RTSP_ETPOST: the tunnel POST request has been performed + * @GST_RTSP_ENOHDCPKEY: HDCP key was not installed * @GST_RTSP_ELAST: last error * * Result codes from the RTSP functions. @@ -104,8 +105,8 @@ typedef enum { GST_RTSP_ETIMEOUT = -14, GST_RTSP_ETGET = -15, GST_RTSP_ETPOST = -16, - - GST_RTSP_ELAST = -17 + GST_RTSP_ENOHDCPKEY = -17, + GST_RTSP_ELAST = -18 } GstRTSPResult; /** diff --git a/gst-libs/gst/rtsp/gstrtsptransport.c b/gst-libs/gst/rtsp/gstrtsptransport.c index ab834a5..8f2e862 100644 --- a/gst-libs/gst/rtsp/gstrtsptransport.c +++ b/gst-libs/gst/rtsp/gstrtsptransport.c @@ -568,16 +568,11 @@ gst_rtsp_transport_as_text (GstRTSPTransport * transport) goto invalid_transport; g_ptr_array_add (strs, g_ascii_strup (tmp, -1)); - if (transport->trans != GST_RTSP_TRANS_RTP || - transport->profile != GST_RTSP_PROFILE_AVP || - transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) { - g_ptr_array_add (strs, g_strdup ("/")); - - if ((tmp = rtsp_transport_ltrans_as_text (transport)) == NULL) - goto invalid_transport; - - g_ptr_array_add (strs, g_ascii_strup (tmp, -1)); - } + g_printf("\n %d transport->lower_transport=%d \n", __LINE__, transport->lower_transport); + g_ptr_array_add (strs, g_strdup ("/")); + if ((tmp = rtsp_transport_ltrans_as_text (transport)) == NULL) + goto invalid_transport; + g_ptr_array_add (strs, g_ascii_strup (tmp, -1)); /* * the order of the following parameters is the same as the one specified in diff --git a/gst-libs/gst/tag/gstxmptag.c b/gst-libs/gst/tag/gstxmptag.c index 1fb7f39..5a51f62 100644 --- a/gst-libs/gst/tag/gstxmptag.c +++ b/gst-libs/gst/tag/gstxmptag.c @@ -173,8 +173,11 @@ xmp_tag_type_get_name (GstXmpTagType tagtype) case GstXmpTagTypeBag: return "rdf:Bag"; default: - g_assert_not_reached (); + break; } + + /* Make compiler happy */ + g_return_val_if_reached (""); } struct _PendingXmpTag diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index f22ff4c..2ad5612 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -877,6 +877,20 @@ gst_video_format_from_fourcc (guint32 fourcc) return GST_VIDEO_FORMAT_IYU1; case GST_MAKE_FOURCC ('A', 'Y', '6', '4'): return GST_VIDEO_FORMAT_AYUV64; +#ifdef GST_EXT_XV_ENHANCEMENT + case GST_MAKE_FOURCC ('S', 'T', '1', '2'): + return GST_VIDEO_FORMAT_ST12; + case GST_MAKE_FOURCC ('S', 'N', '1', '2'): + return GST_VIDEO_FORMAT_SN12; + case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): + return GST_VIDEO_FORMAT_SUYV; + case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'): + return GST_VIDEO_FORMAT_SUY2; + case GST_MAKE_FOURCC ('S', '4', '2', '0'): + return GST_VIDEO_FORMAT_S420; + case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): + return GST_VIDEO_FORMAT_SYVY; +#endif default: return GST_VIDEO_FORMAT_UNKNOWN; } @@ -944,6 +958,20 @@ gst_video_format_to_fourcc (GstVideoFormat format) return GST_MAKE_FOURCC ('I', 'Y', 'U', '1'); case GST_VIDEO_FORMAT_AYUV64: return GST_MAKE_FOURCC ('A', 'Y', '6', '4'); +#ifdef GST_EXT_XV_ENHANCEMENT + case GST_VIDEO_FORMAT_ST12: + return GST_MAKE_FOURCC ('S', 'T', '1', '2'); + case GST_VIDEO_FORMAT_SN12: + return GST_MAKE_FOURCC ('S', 'N', '1', '2'); + case GST_VIDEO_FORMAT_SUYV: + return GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'); + case GST_VIDEO_FORMAT_SUY2: + return GST_MAKE_FOURCC ('S', 'U', 'Y', '2'); + case GST_VIDEO_FORMAT_S420: + return GST_MAKE_FOURCC ('S', '4', '2', '0'); + case GST_VIDEO_FORMAT_SYVY: + return GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'); +#endif default: return 0; } diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h old mode 100644 new mode 100755 index 36750e9..f45cc75 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -33,7 +33,7 @@ G_BEGIN_DECLS * @GST_VIDEO_FORMAT_I420: planar 4:2:0 YUV * @GST_VIDEO_FORMAT_YV12: planar 4:2:0 YVU (like I420 but UV planes swapped) * @GST_VIDEO_FORMAT_YUY2: packed 4:2:2 YUV (Y0-U0-Y1-V0 Y2-U2-Y3-V2 Y4 ...) - * @GST_VIDEO_FORMAT_UYVY: packed 4:2:2 YUV (U0-Y0-V0-Y1 U2-Y2-V2-Y3 U4 ...) + * @GST_VIDEO_FORMAT_UYVY: packed 4:2:2 YUV (U0-Y0-V0-Y1 U2-Y2-V2-Y3 U4 ...) * @GST_VIDEO_FORMAT_AYUV: packed 4:4:4 YUV with alpha channel (A0-Y0-U0-V0 ...) * @GST_VIDEO_FORMAT_RGBx: sparse rgb packed into 32 bit, space last * @GST_VIDEO_FORMAT_BGRx: sparse reverse rgb packed into 32 bit, space last @@ -119,6 +119,14 @@ typedef enum { GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_r210 +#ifdef GST_EXT_XV_ENHANCEMENT +, GST_VIDEO_FORMAT_ST12, + GST_VIDEO_FORMAT_SN12, + GST_VIDEO_FORMAT_SUYV, + GST_VIDEO_FORMAT_SUY2, + GST_VIDEO_FORMAT_S420, + GST_VIDEO_FORMAT_SYVY +#endif } GstVideoFormat; #define GST_VIDEO_BYTE1_MASK_32 "0xFF000000" @@ -264,13 +272,13 @@ typedef enum { #define GST_VIDEO_CAPS_RGBx \ __GST_VIDEO_CAPS_MAKE_32 (1, 2, 3) - + #define GST_VIDEO_CAPS_xRGB \ __GST_VIDEO_CAPS_MAKE_32 (2, 3, 4) - + #define GST_VIDEO_CAPS_BGRx \ __GST_VIDEO_CAPS_MAKE_32 (3, 2, 1) - + #define GST_VIDEO_CAPS_xBGR \ __GST_VIDEO_CAPS_MAKE_32 (4, 3, 2) @@ -278,13 +286,13 @@ typedef enum { #define GST_VIDEO_CAPS_RGBA \ __GST_VIDEO_CAPS_MAKE_32A (1, 2, 3, 4) - + #define GST_VIDEO_CAPS_ARGB \ __GST_VIDEO_CAPS_MAKE_32A (2, 3, 4, 1) - + #define GST_VIDEO_CAPS_BGRA \ __GST_VIDEO_CAPS_MAKE_32A (3, 2, 1, 4) - + #define GST_VIDEO_CAPS_ABGR \ __GST_VIDEO_CAPS_MAKE_32A (4, 3, 2, 1) @@ -300,9 +308,9 @@ typedef enum { #define GST_VIDEO_CAPS_BGRx_HOST_ENDIAN \ GST_VIDEO_CAPS_xRGB #endif - + /* 15/16 bit */ - + #define GST_VIDEO_CAPS_RGB_16 \ __GST_VIDEO_CAPS_MAKE_16 (1, 2, 3) @@ -342,9 +350,9 @@ typedef enum { */ #define GST_VIDEO_CAPS_RGB8_PALETTED \ "video/x-raw-rgb, bpp = (int)8, depth = (int)8, " \ - "width = "GST_VIDEO_SIZE_RANGE" , " \ + "width = " GST_VIDEO_SIZE_RANGE ", " \ "height = " GST_VIDEO_SIZE_RANGE ", " \ - "framerate = "GST_VIDEO_FPS_RANGE + "framerate = " GST_VIDEO_FPS_RANGE /** * GST_VIDEO_CAPS_YUV: diff --git a/gst-plugins-base-tools.manifest b/gst-plugins-base-tools.manifest new file mode 100755 index 0000000..fa9a0cf --- /dev/null +++ b/gst-plugins-base-tools.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gst-plugins-base.manifest b/gst-plugins-base.manifest new file mode 100755 index 0000000..a76fdba --- /dev/null +++ b/gst-plugins-base.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index 717cf10..818c895 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -119,6 +119,13 @@ GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform, #define STATIC_CAPS \ GST_STATIC_CAPS ( \ + "audio/x-lpcm, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 2 ], " \ + "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ + "width = (int) [1,32], " \ + "depth = (int) [ 1, 32 ], " \ + "signed = (boolean) { true, false }; " \ "audio/x-raw-float, " \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ @@ -306,7 +313,8 @@ gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt) fmt->endianness = G_BYTE_ORDER; fmt->is_int = - (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0); + (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) || + (strcmp (gst_structure_get_name (structure), "audio/x-lpcm") == 0); /* parse common fields */ if (!gst_structure_get_int (structure, "channels", &fmt->channels)) diff --git a/gst/ffmpegcolorspace/gstffmpegcodecmap.c b/gst/ffmpegcolorspace/gstffmpegcodecmap.c index a161a65..a27087d 100644 --- a/gst/ffmpegcolorspace/gstffmpegcodecmap.c +++ b/gst/ffmpegcolorspace/gstffmpegcodecmap.c @@ -2,6 +2,7 @@ * Copyright (C) <1999> Erik Walthinsen * This file: * Copyright (c) 2002-2004 Ronald Bultje + * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,6 +18,9 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * * Modifications by Samsung Electronics Co., Ltd. + * 1. Support samsung extension format */ #ifdef HAVE_CONFIG_H @@ -630,6 +634,7 @@ gst_ffmpeg_caps_to_pixfmt (const GstCaps * caps, break; case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC ('I', 'T', 'L', 'V'): context->pix_fmt = PIX_FMT_UYVY422; break; case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'): diff --git a/gst/ffmpegcolorspace/gstffmpegcolorspace.c b/gst/ffmpegcolorspace/gstffmpegcolorspace.c index 7b1c18f..0ee1d46 100644 --- a/gst/ffmpegcolorspace/gstffmpegcolorspace.c +++ b/gst/ffmpegcolorspace/gstffmpegcolorspace.c @@ -2,6 +2,7 @@ * Copyright (C) <1999> Erik Walthinsen * This file: * Copyright (C) 2003 Ronald Bultje + * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,6 +18,9 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * * Modifications by Samsung Electronics Co., Ltd. + * 1. Support samsung extension format */ /** @@ -47,7 +51,7 @@ GST_DEBUG_CATEGORY (ffmpegcolorspace_performance); #define FFMPEGCSP_VIDEO_CAPS \ "video/x-raw-yuv, width = "GST_VIDEO_SIZE_RANGE" , " \ "height="GST_VIDEO_SIZE_RANGE",framerate="GST_VIDEO_FPS_RANGE"," \ - "format= (fourcc) { I420 , NV12 , NV21 , YV12 , YUY2 , Y42B , Y444 , YUV9 , YVU9 , Y41B , Y800 , Y8 , GREY , Y16 , UYVY , YVYU , IYU1 , v308 , AYUV , A420 , SUYV , SYVY , S420 } ;" \ + "format= (fourcc) { I420 , NV12 , NV21 , YV12 , YUY2 , Y42B , Y444 , YUV9 , YVU9 , Y41B , Y800 , Y8 , GREY , Y16 , UYVY , YVYU , IYU1 , v308 , AYUV , A420 , SUYV , SYVY , S420 , ITLV } ;" \ GST_VIDEO_CAPS_RGB";" \ GST_VIDEO_CAPS_BGR";" \ GST_VIDEO_CAPS_RGBx";" \ diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c old mode 100644 new mode 100755 index 8bcadde..55a092f --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -405,6 +405,7 @@ struct _GstDecodeChain GstPad *pad; /* srcpad that caused creation of this chain */ + gboolean drained; /* TRUE if the all children are drained */ gboolean demuxer; /* TRUE if elements->data is a demuxer */ gboolean seekable; /* TRUE if this chain ends on a demuxer and is seekable */ GList *elements; /* All elements in this group, first @@ -2266,6 +2267,14 @@ type_found (GstElement * typefind, guint probability, goto exit; } +#ifdef GST_EXT_DECODEBIN2_QUEUESIZE + if (gst_structure_has_name (gst_caps_get_structure (caps, 0), "application/x-hls") || + gst_structure_has_name (gst_caps_get_structure (caps, 0), "application/x-ss")) { + GST_DEBUG_OBJECT (decode_bin, "decodebin2 got hls/ss caps.. set queue max-size-time to 1 sec"); + decode_bin->max_size_time = 1 * GST_SECOND; + } +#endif + /* FIXME: we can only deal with one type, we don't yet support dynamically changing * caps from the typefind element */ if (decode_bin->have_type || decode_bin->decode_chain) @@ -2915,6 +2924,9 @@ gst_decode_group_new (GstDecodeBin * dbin, GstDecodeChain * parent) GstDecodeGroup *group = g_slice_new0 (GstDecodeGroup); GstElement *mq; gboolean seekable; +#ifdef GST_EXT_DECODEBIN2_MODIFICATION + gboolean smooth_stream_demuxer_last = FALSE; +#endif GST_DEBUG_OBJECT (dbin, "Creating new group %p with parent chain %p", group, parent); @@ -2926,8 +2938,25 @@ gst_decode_group_new (GstDecodeBin * dbin, GstDecodeChain * parent) if (G_UNLIKELY (!group->multiqueue)) goto missing_multiqueue; +#ifdef GST_EXT_DECODEBIN2_MODIFICATION + /*Check if last parent elment is smooth streaming demuxer.*/ + if (parent && parent->demuxer) + { + GstElement *element = + ((GstDecodeElement *) parent->elements->data)->element; + if(g_strrstr(GST_ELEMENT_NAME(element), "dashdemux")) + smooth_stream_demuxer_last = TRUE; + } + + /* default is for use-buffering is FALSE + We should disable buffering in multiqueue after smooth streaming + demuxers like dashdemux because they are fake demuxers.*/ + if (dbin->use_buffering && !smooth_stream_demuxer_last) +#else /* default is for use-buffering is FALSE */ - if (dbin->use_buffering) { + if (dbin->use_buffering) +#endif + { g_object_set (mq, "use-buffering", TRUE, "low-percent", dbin->low_percent, @@ -3120,7 +3149,6 @@ drain_and_switch_group (GstDecodeGroup * group, GstDecodePad * drainpad, gboolean * last_group, gboolean * drained, gboolean * switched) { gboolean handled = FALSE; - gboolean alldrained = TRUE; GList *tmp; GST_DEBUG ("Checking group %p (target pad %s:%s)", @@ -3133,6 +3161,7 @@ drain_and_switch_group (GstDecodeGroup * group, GstDecodePad * drainpad, /* Figure out if all our chains are drained with the * new information */ + group->drained = TRUE; for (tmp = group->children; tmp; tmp = tmp->next) { GstDecodeChain *chain = (GstDecodeChain *) tmp->data; gboolean subdrained = FALSE; @@ -3141,13 +3170,13 @@ drain_and_switch_group (GstDecodeGroup * group, GstDecodePad * drainpad, drain_and_switch_chains (chain, drainpad, last_group, &subdrained, switched); if (!subdrained) - alldrained = FALSE; + group->drained = FALSE; } beach: GST_DEBUG ("group %p (last_group:%d, drained:%d, switched:%d, handled:%d)", - group, *last_group, alldrained, *switched, handled); - *drained = alldrained; + group, *last_group, group->drained, *switched, handled); + *drained = group->drained; return handled; } @@ -3163,6 +3192,11 @@ drain_and_switch_chains (GstDecodeChain * chain, GstDecodePad * drainpad, CHAIN_MUTEX_LOCK (chain); + /* Definitely can't be in drained chains */ + if (G_UNLIKELY (chain->drained)) { + goto beach; + } + if (chain->endpad) { /* Check if we're reached the target endchain */ if (chain == drainpad->chain) { @@ -3171,7 +3205,7 @@ drain_and_switch_chains (GstDecodeChain * chain, GstDecodePad * drainpad, handled = TRUE; } - *drained = chain->endpad->drained; + chain->drained = chain->endpad->drained; goto beach; } @@ -3199,11 +3233,11 @@ drain_and_switch_chains (GstDecodeChain * chain, GstDecodePad * drainpad, chain->next_groups = g_list_delete_link (chain->next_groups, chain->next_groups); *switched = TRUE; - *drained = FALSE; + chain->drained = FALSE; } else { GST_DEBUG ("Group %p was the last in chain %p", chain->active_group, chain); - *drained = TRUE; + chain->drained = TRUE; /* We're drained ! */ } } @@ -3213,7 +3247,9 @@ beach: CHAIN_MUTEX_UNLOCK (chain); GST_DEBUG ("Chain %p (handled:%d, last_group:%d, drained:%d, switched:%d)", - chain, handled, *last_group, *drained, *switched); + chain, handled, *last_group, chain->drained, *switched); + + *drained = chain->drained; if (*drained) g_signal_emit (dbin, gst_decode_bin_signals[SIGNAL_DRAINED], 0, NULL); diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c old mode 100644 new mode 100755 index b6e62d3..1f0f9c1 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -1276,7 +1276,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) GstBin *bin; GstPad *pad; GstElement *head = NULL, *prev = NULL, *elem = NULL; - GstPlugin *p; + GstPlugin *p = NULL; chain = g_new0 (GstPlayVideoChain, 1); chain->chain.playsink = playsink; @@ -1336,6 +1336,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) gst_object_ref_sink (bin); gst_bin_add (bin, chain->sink); +#ifndef GST_EXT_XV_ENHANCEMENT /* decouple decoder from sink, this improves playback quite a lot since the * decoder can continue while the sink blocks for synchronisation. We don't * need a lot of buffers as this consumes a lot of memory and we don't want @@ -1354,6 +1355,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) gst_bin_add (bin, chain->queue); head = prev = chain->queue; } +#endif if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { GST_DEBUG_OBJECT (playsink, "creating videoconverter"); diff --git a/gst/subparse/Makefile.am b/gst/subparse/Makefile.am index 4a33bd4..d8e4617 100644 --- a/gst/subparse/Makefile.am +++ b/gst/subparse/Makefile.am @@ -24,6 +24,12 @@ libgstsubparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstsubparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) libgstsubparse_la_LIBTOOLFLAGS = --tag=disable-static +if USE_XML +libgstsubparse_la_CFLAGS += $(XML_CFLAGS) +libgstsubparse_la_LIBADD += $(XML_LIBS) +endif + + noinst_HEADERS = \ gstssaparse.h \ gstsubparse.h \ diff --git a/gst/subparse/gstsubparse.c b/gst/subparse/gstsubparse.c old mode 100644 new mode 100755 index 9c31b54..5d1d242 --- a/gst/subparse/gstsubparse.c +++ b/gst/subparse/gstsubparse.c @@ -36,15 +36,27 @@ #include "mpl2parse.h" #include "qttextparse.h" +#ifdef GST_EXT_ENABLE_SMI +#ifdef GST_DISABLE_XML +#undef GST_DISABLE_XML +#endif +#endif + GST_DEBUG_CATEGORY (sub_parse_debug); -#define DEFAULT_ENCODING NULL +#define DEFAULT_ENCODING NULL +#ifdef SUBPARSE_MODIFICATION +#define DEFAULT_CURRENT_LANGUAGE NULL +#endif enum { PROP_0, PROP_ENCODING, - PROP_VIDEOFPS + PROP_VIDEOFPS, +#ifdef SUBPARSE_MODIFICATION + PROP_EXTSUB_CURRENT_LANGUAGE +#endif }; static void @@ -172,7 +184,12 @@ gst_sub_parse_dispose (GObject * object) g_string_free (subparse->textbuf, TRUE); subparse->textbuf = NULL; } - +#ifdef SUBPARSE_MODIFICATION + if (subparse->state.current_language) { + g_free (subparse->state.current_language); + subparse->state.current_language = NULL; + } +#endif GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); } @@ -205,6 +222,13 @@ gst_sub_parse_class_init (GstSubParseClass * klass) "and the subtitle format requires it subtitles may be out of sync.", 0, 1, G_MAXINT, 1, 24000, 1001, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#ifdef SUBPARSE_MODIFICATION + g_object_class_install_property (object_class, PROP_EXTSUB_CURRENT_LANGUAGE, + g_param_spec_string ("current-language", "Current language", + "Current language of the subtitle in external subtitle case.", + DEFAULT_CURRENT_LANGUAGE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif } static void @@ -227,6 +251,7 @@ gst_sub_parse_init (GstSubParse * subparse) subparse->textbuf = g_string_new (NULL); subparse->parser_type = GST_SUB_PARSE_FORMAT_UNKNOWN; subparse->flushing = FALSE; + subparse->discont_sent = FALSE; gst_segment_init (&subparse->segment, GST_FORMAT_TIME); subparse->need_segment = TRUE; subparse->encoding = g_strdup (DEFAULT_ENCODING); @@ -319,24 +344,23 @@ gst_sub_parse_src_event (GstPad * pad, GstEvent * event) goto beach; } + /* Apply the seek to our segment */ + gst_segment_set_seek (&self->segment, rate, format, self->segment_flags, + start_type, start, stop_type, stop, &update); + + GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT, + &self->segment); + + self->next_offset = 0; + self->need_segment = TRUE; + /* Convert that seek to a seeking in bytes at position 0, FIXME: could use an index */ ret = gst_pad_push_event (self->sinkpad, gst_event_new_seek (rate, GST_FORMAT_BYTES, self->segment_flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0)); - if (ret) { - /* Apply the seek to our segment */ - gst_segment_set_seek (&self->segment, rate, format, self->segment_flags, - start_type, start, stop_type, stop, &update); - - GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT, - &self->segment); - - self->next_offset = 0; - - self->need_segment = TRUE; - } else { + if (!ret) { GST_WARNING_OBJECT (self, "seek to 0 bytes failed"); } @@ -381,6 +405,16 @@ gst_sub_parse_set_property (GObject * object, guint prop_id, } break; } +#ifdef SUBPARSE_MODIFICATION + case PROP_EXTSUB_CURRENT_LANGUAGE: + subparse->state.current_language = g_value_dup_string (value); + subparse->state.msl_language = g_value_dup_string (value); + GST_LOG_OBJECT (subparse, "subtitle current language set to %s", + GST_STR_NULL (subparse->state.current_language)); + GST_LOG_OBJECT (subparse, "subtitle msl language set to %s", + GST_STR_NULL (subparse->state.msl_language)); + break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -402,6 +436,12 @@ gst_sub_parse_get_property (GObject * object, guint prop_id, case PROP_VIDEOFPS: gst_value_set_fraction (value, subparse->fps_n, subparse->fps_d); break; +#ifdef SUBPARSE_MODIFICATION + case PROP_EXTSUB_CURRENT_LANGUAGE: + g_value_set_string (value, subparse->state.current_language); + GST_LOG("************getting property to %s*********************",subparse->state.current_language); + break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -508,6 +548,10 @@ convert_encoding (GstSubParse * self, const gchar * str, gsize len, g_free (self->detected_encoding); self->detected_encoding = NULL; g_error_free (err); +#ifdef SUBPARSE_MODIFICATION + /* You must ensure an error is NULL before it's set */ + err = NULL; +#endif } /* Otherwise check if it's UTF8 */ @@ -540,9 +584,22 @@ convert_encoding (GstSubParse * self, const gchar * str, gsize len, GST_WARNING_OBJECT (self, "could not convert string from '%s' to UTF-8: %s", encoding, err->message); g_error_free (err); - +#ifdef SUBPARSE_MODIFICATION + /* You must ensure an error is NULL before it's set */ + err = NULL; + if(!strcmp(self->encoding,"EUC-KR")) + { + GST_WARNING("failback case is occure with EUC-KR,so going with CP949 "); + g_free(self->encoding); + self->encoding = g_strdup("CP949"); + ret = gst_convert_to_utf8 (str, len, encoding, consumed, &err); + } else { +#endif /* invalid input encoding, fall back to ISO-8859-15 (always succeeds) */ - ret = gst_convert_to_utf8 (str, len, "ISO-8859-15", consumed, NULL); + ret = gst_convert_to_utf8 (str, len, "ISO-8859-15", consumed, NULL); +#ifdef SUBPARSE_MODIFICATION + } +#endif } GST_LOG_OBJECT (self, @@ -1197,6 +1254,11 @@ parser_state_init (ParserState * state) state->max_duration = 0; /* no limit */ state->state = 0; state->segment = NULL; +#ifdef SUBPARSE_MODIFICATION + state->language_list = NULL; + state->current_language = NULL; + state->langlist_msg_posted = FALSE; +#endif } static void @@ -1383,6 +1445,8 @@ gst_sub_parse_format_autodetect (GstSubParse * self) case GST_SUB_PARSE_FORMAT_SAMI: self->parse_line = parse_sami; sami_context_init (&self->state); + GST_LOG("************setting property to %s*********************", self->state.current_language); + sami_context_change_language (&self->state); return gst_caps_new_simple ("text/x-pango-markup", NULL); #endif case GST_SUB_PARSE_FORMAT_TMPLAYER: @@ -1443,14 +1507,13 @@ feed_textbuf (GstSubParse * self, GstBuffer * buf) self->offset = GST_BUFFER_OFFSET (buf) + GST_BUFFER_SIZE (buf); self->next_offset = self->offset; - + GST_INFO("Pushing in the adapter"); gst_adapter_push (self->adapter, buf); input = convert_encoding (self, (const gchar *) gst_adapter_peek (self->adapter, gst_adapter_available (self->adapter)), (gsize) gst_adapter_available (self->adapter), &consumed); - if (input && consumed > 0) { self->textbuf = g_string_append (self->textbuf, input); gst_adapter_flush (self->adapter, consumed); @@ -1459,13 +1522,65 @@ feed_textbuf (GstSubParse * self, GstBuffer * buf) g_free (input); } +#ifdef SUBPARSE_MODIFICATION +static gchar* +get_next_sami_sync_line (gchar * line, guint* offset) +{ + const char *line_end = NULL; + gchar* sync_line = NULL; + int have_r = 0; + + line_end = strstr (line, "first_buffer) { self->detected_encoding = detect_encoding ((gchar *) GST_BUFFER_DATA (buf), @@ -1474,7 +1589,17 @@ handle_buffer (GstSubParse * self, GstBuffer * buf) self->state.fps_n = self->fps_n; self->state.fps_d = self->fps_d; } - + if (!strcmp ((const char*)GST_BUFFER_DATA (buf), "eos")){ + GST_DEBUG_OBJECT(self,"eos buffer is recieved"); + if (GST_BUFFER_FLAG_IS_SET(buf,GST_BUFFER_FLAG_GAP)) { + GST_DEBUG_OBJECT(self,"eos buffer with flag is recieved recieved"); + ret = gst_pad_push (self->srcpad, buf); + return ret; + } + } + discont = GST_BUFFER_IS_DISCONT (buf); + if(discont) + self->discont_sent = FALSE; feed_textbuf (self, buf); /* make sure we know the format */ @@ -1501,9 +1626,161 @@ handle_buffer (GstSubParse * self, GstBuffer * buf) while (!self->flushing && (line = get_next_line (self))) { guint offset = 0; - +#ifdef SUBPARSE_MODIFICATION + guint suboffset = 0; + gchar* sync_line = NULL; +#endif /* Set segment on our parser state machine */ self->state.segment = &self->segment; +#ifdef SUBPARSE_MODIFICATION + if (self->parser_type == GST_SUB_PARSE_FORMAT_SAMI) { + do { + /* Now parse the line, out of segment lines will just return NULL */ + sync_line = get_next_sami_sync_line(line + offset, &suboffset); + offset += suboffset; + GST_LOG_OBJECT (self, "Parsing line '%s'", sync_line); + subtitle = self->parse_line (&self->state, sync_line); + g_free (sync_line); + sync_line = NULL; + + if (!self->state.langlist_msg_posted && self->state.language_list) { + if(self->state.language_list) { + m = gst_message_new_element (GST_OBJECT_CAST (self), gst_structure_new("Ext_Sub_Language_List", + "lang_list", G_TYPE_POINTER, self->state.language_list, NULL)); + + gst_element_post_message (GST_ELEMENT_CAST (self), m); + self->state.langlist_msg_posted = TRUE; + } + GST_DEBUG_OBJECT (self, "LANGLIST POSTED with current language as : %s ",self->state.current_language); + } + GST_DEBUG_OBJECT (self, "parse_line returned %x", subtitle); + + if (subtitle) { + guint subtitle_len = strlen (subtitle); + + /* +1 for terminating NUL character */ + ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, + GST_BUFFER_OFFSET_NONE, subtitle_len + 1, + GST_PAD_CAPS (self->srcpad), &buf); + + if (ret == GST_FLOW_OK) { + /* copy terminating NUL character as well */ + memcpy (GST_BUFFER_DATA (buf), subtitle, subtitle_len + 1); + GST_BUFFER_SIZE (buf) = subtitle_len; + GST_BUFFER_TIMESTAMP (buf) = self->state.start_time; + GST_BUFFER_DURATION (buf) = self->state.duration; + if (discont && !counter) { + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG("setting the true for discont flag and self is %p with ts is %" GST_TIME_FORMAT "\n",self,GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf))); + self->discont_sent = TRUE; + counter++; + } else if (!self->discont_sent && !counter) { + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG("setting the true for discont flag and self is %p with ts is %" GST_TIME_FORMAT "\n",self,GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf))); + self->discont_sent = TRUE; + counter++; + } + + /* in some cases (e.g. tmplayer) we can only determine the duration + * of a text chunk from the timestamp of the next text chunk; in those + * cases, we probably want to limit the duration to something + * reasonable, so we don't end up showing some text for e.g. 40 seconds + * just because nothing else is being said during that time */ + if (self->state.max_duration > 0 && GST_BUFFER_DURATION_IS_VALID (buf)) { + if (GST_BUFFER_DURATION (buf) > self->state.max_duration) + GST_BUFFER_DURATION (buf) = self->state.max_duration; + } + + gst_segment_set_last_stop (&self->segment, GST_FORMAT_TIME, self->state.start_time); + + GST_DEBUG_OBJECT (self, "Sending text '%s', %" GST_TIME_FORMAT " + %" + GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time), + GST_TIME_ARGS (self->state.duration)); + + ret = gst_pad_push (self->srcpad, buf); + } + + /* move this forward (the tmplayer parser needs this) */ + if (self->state.duration != GST_CLOCK_TIME_NONE) + self->state.start_time += self->state.duration; + + g_free (subtitle); + subtitle = NULL; + } + } while (suboffset); + g_free (line); + line = NULL; + } + + else { + /* Now parse the line, out of segment lines will just return NULL */ + GST_LOG_OBJECT (self, "Parsing line '%s'", line + offset); + subtitle = self->parse_line (&self->state, line + offset); + g_free (line); + + GST_DEBUG_OBJECT (self, "parse_line returned %x", subtitle); + + if (subtitle) { + guint subtitle_len = strlen (subtitle); + + /* +1 for terminating NUL character */ + ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, + GST_BUFFER_OFFSET_NONE, subtitle_len + 1, + GST_PAD_CAPS (self->srcpad), &buf); + + if (ret == GST_FLOW_OK) { + /* copy terminating NUL character as well */ + memcpy (GST_BUFFER_DATA (buf), subtitle, subtitle_len + 1); + GST_BUFFER_SIZE (buf) = subtitle_len; + GST_BUFFER_TIMESTAMP (buf) = self->state.start_time; + GST_BUFFER_DURATION (buf) = self->state.duration; + + /* in some cases (e.g. tmplayer) we can only determine the duration + * of a text chunk from the timestamp of the next text chunk; in those + * cases, we probably want to limit the duration to something + * reasonable, so we don't end up showing some text for e.g. 40 seconds + * just because nothing else is being said during that time */ + if (self->state.max_duration > 0 && GST_BUFFER_DURATION_IS_VALID (buf)) { + if (GST_BUFFER_DURATION (buf) > self->state.max_duration) + GST_BUFFER_DURATION (buf) = self->state.max_duration; + } + + gst_segment_set_last_stop (&self->segment, GST_FORMAT_TIME, + self->state.start_time); + + GST_DEBUG_OBJECT (self, "Sending text '%s', %" GST_TIME_FORMAT " + %" + GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time), + GST_TIME_ARGS (self->state.duration)); + if (discont && !counter) { + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG("setting the true for discont flag and self is %p with ts is %" GST_TIME_FORMAT "\n",self,GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf))); + self->discont_sent = TRUE; + counter++; + } else if (!self->discont_sent && !counter) { + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG("setting the true for discont flag and self is %p with ts is %" GST_TIME_FORMAT "\n",self,GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf))); + self->discont_sent = TRUE; + counter++; + } + GST_DEBUG_OBJECT (self, "Sent buffer with TS %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf))); + + ret = gst_pad_push (self->srcpad, buf); + } + + /* move this forward (the tmplayer parser needs this) */ + if (self->state.duration != GST_CLOCK_TIME_NONE) + self->state.start_time += self->state.duration; + + g_free (subtitle); + subtitle = NULL; + } + } + + if (ret != GST_FLOW_OK) { + GST_DEBUG_OBJECT (self, "flow: %s", gst_flow_get_name (ret)); + break; + } +#else /* Now parse the line, out of segment lines will just return NULL */ GST_LOG_OBJECT (self, "Parsing line '%s'", line + offset); subtitle = self->parse_line (&self->state, line + offset); @@ -1556,6 +1833,7 @@ handle_buffer (GstSubParse * self, GstBuffer * buf) break; } } +#endif } return ret; @@ -1576,7 +1854,7 @@ gst_sub_parse_chain (GstPad * sinkpad, GstBuffer * buf) gst_pad_push_event (self->srcpad, gst_event_new_new_segment (FALSE, self->segment.rate, self->segment.format, - self->segment.last_stop, self->segment.stop, self->segment.time)); + self->segment.start, self->segment.stop, self->segment.time)); self->need_segment = FALSE; } @@ -1625,7 +1903,7 @@ gst_sub_parse_sink_event (GstPad * pad, GstEvent * event) &stop, &time); GST_DEBUG_OBJECT (self, "newsegment (%s)", gst_format_get_name (format)); - + self->need_segment = TRUE; if (format == GST_FORMAT_TIME) { gst_segment_set_newsegment (&self->segment, update, rate, format, start, stop, time); diff --git a/gst/subparse/gstsubparse.h b/gst/subparse/gstsubparse.h old mode 100644 new mode 100755 index 5731d91..4132e1c --- a/gst/subparse/gstsubparse.h +++ b/gst/subparse/gstsubparse.h @@ -24,6 +24,8 @@ #include #include +#define SUBPARSE_MODIFICATION + GST_DEBUG_CATEGORY_EXTERN (sub_parse_debug); #define GST_CAT_DEFAULT sub_parse_debug @@ -68,6 +70,12 @@ typedef struct { gpointer user_data; gboolean have_internal_fps; /* If TRUE don't overwrite fps by property */ gint fps_n, fps_d; /* used by frame based parsers */ +#ifdef SUBPARSE_MODIFICATION + GList* language_list; + gchar* current_language; + gchar *msl_language; + gboolean langlist_msg_posted; +#endif } ParserState; typedef gchar* (*Parser) (ParserState *state, const gchar *line); @@ -99,6 +107,7 @@ struct _GstSubParse { gboolean need_segment; gboolean flushing; + gboolean discont_sent; gboolean valid_utf8; gchar *detected_encoding; gchar *encoding; @@ -106,7 +115,7 @@ struct _GstSubParse { gboolean first_buffer; /* used by frame based parsers */ - gint fps_n, fps_d; + gint fps_n, fps_d; }; struct _GstSubParseClass { diff --git a/gst/subparse/samiparse.c b/gst/subparse/samiparse.c old mode 100644 new mode 100755 index 135748a..01205fb --- a/gst/subparse/samiparse.c +++ b/gst/subparse/samiparse.c @@ -1,5 +1,5 @@ /* GStreamer SAMI subtitle parser - * Copyright (c) 2006 Young-Ho Cha + * Copyright (c) 2006, 2013 Young-Ho Cha * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -13,14 +13,16 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ +#define _GNU_SOURCE #include "samiparse.h" -#include +#include #include +#include #define ITALIC_TAG 'i' #define SPAN_TAG 's' @@ -28,8 +30,18 @@ #define RT_TAG 't' #define CLEAR_TAG '0' +typedef struct _HtmlParser HtmlParser; +typedef struct _HtmlContext HtmlContext; typedef struct _GstSamiContext GstSamiContext; - +#ifdef SUBPARSE_MODIFICATION +typedef struct _LanguageStruct GstLangStruct; +struct _LanguageStruct +{ + gchar *language_code; + gchar *language_key; +}; +#define MAX_LANGUAGE 10 +#endif struct _GstSamiContext { GString *buf; /* buffer to collect content */ @@ -43,14 +55,634 @@ struct _GstSamiContext * that tags can be closed properly on * 'sync' tags. See _context_push_state() * and _context_pop_state(). */ - htmlParserCtxtPtr htmlctxt; /* html parser context */ + HtmlContext *htmlctxt; /* html parser context */ gboolean has_result; /* set when ready to push out result */ gboolean in_sync; /* flag to avoid appending anything except the * content of the sync elements to buf */ guint64 time1; /* previous start attribute in sync tag */ guint64 time2; /* current start attribute in sync tag */ +#ifdef SUBPARSE_MODIFICATION + guint64 time3; /* To store the last current time when language is changed */ + GList *lang_list; /* Language list for an external subtitle file */ + gchar *current_language; /* Current language parsed */ + gchar *desired_language; /* Language set by user */ + gboolean language_changed; /* language changed signal */ + gboolean end_body; /* reached */ +#endif +}; + +struct _HtmlParser +{ + void (*start_element) (HtmlContext * ctx, + const gchar * name, const gchar ** attr, gpointer user_data); + void (*end_element) (HtmlContext * ctx, + const gchar * name, gpointer user_data); + void (*text) (HtmlContext * ctx, + const gchar * text, gsize text_len, gpointer user_data); +}; + +struct _HtmlContext +{ + const HtmlParser *parser; + gpointer user_data; + GString *buf; +}; + +static HtmlContext * +html_context_new (HtmlParser * parser, gpointer user_data) +{ + HtmlContext *ctxt = (HtmlContext *) g_new0 (HtmlContext, 1); + ctxt->parser = parser; + ctxt->user_data = user_data; + ctxt->buf = g_string_new (NULL); + return ctxt; +} + +static void +html_context_free (HtmlContext * ctxt) +{ + g_string_free (ctxt->buf, TRUE); + g_free (ctxt); +} + +struct EntityMap +{ + const gunichar unescaped; + const gchar *escaped; +}; + +struct EntityMap XmlEntities[] = { + {34, "quot;"}, + {38, "amp;"}, + {39, "apos;"}, + {60, "lt;"}, + {62, "gt;"}, + {0, NULL}, }; +struct EntityMap HtmlEntities[] = { +/* nbsp will handle manually +{ 160, "nbsp;" }, */ + {161, "iexcl;"}, + {162, "cent;"}, + {163, "pound;"}, + {164, "curren;"}, + {165, "yen;"}, + {166, "brvbar;"}, + {167, "sect;"}, + {168, "uml;"}, + {169, "copy;"}, + {170, "ordf;"}, + {171, "laquo;"}, + {172, "not;"}, + {173, "shy;"}, + {174, "reg;"}, + {175, "macr;"}, + {176, "deg;"}, + {177, "plusmn;"}, + {178, "sup2;"}, + {179, "sup3;"}, + {180, "acute;"}, + {181, "micro;"}, + {182, "para;"}, + {183, "middot;"}, + {184, "cedil;"}, + {185, "sup1;"}, + {186, "ordm;"}, + {187, "raquo;"}, + {188, "frac14;"}, + {189, "frac12;"}, + {190, "frac34;"}, + {191, "iquest;"}, + {192, "Agrave;"}, + {193, "Aacute;"}, + {194, "Acirc;"}, + {195, "Atilde;"}, + {196, "Auml;"}, + {197, "Aring;"}, + {198, "AElig;"}, + {199, "Ccedil;"}, + {200, "Egrave;"}, + {201, "Eacute;"}, + {202, "Ecirc;"}, + {203, "Euml;"}, + {204, "Igrave;"}, + {205, "Iacute;"}, + {206, "Icirc;"}, + {207, "Iuml;"}, + {208, "ETH;"}, + {209, "Ntilde;"}, + {210, "Ograve;"}, + {211, "Oacute;"}, + {212, "Ocirc;"}, + {213, "Otilde;"}, + {214, "Ouml;"}, + {215, "times;"}, + {216, "Oslash;"}, + {217, "Ugrave;"}, + {218, "Uacute;"}, + {219, "Ucirc;"}, + {220, "Uuml;"}, + {221, "Yacute;"}, + {222, "THORN;"}, + {223, "szlig;"}, + {224, "agrave;"}, + {225, "aacute;"}, + {226, "acirc;"}, + {227, "atilde;"}, + {228, "auml;"}, + {229, "aring;"}, + {230, "aelig;"}, + {231, "ccedil;"}, + {232, "egrave;"}, + {233, "eacute;"}, + {234, "ecirc;"}, + {235, "euml;"}, + {236, "igrave;"}, + {237, "iacute;"}, + {238, "icirc;"}, + {239, "iuml;"}, + {240, "eth;"}, + {241, "ntilde;"}, + {242, "ograve;"}, + {243, "oacute;"}, + {244, "ocirc;"}, + {245, "otilde;"}, + {246, "ouml;"}, + {247, "divide;"}, + {248, "oslash;"}, + {249, "ugrave;"}, + {250, "uacute;"}, + {251, "ucirc;"}, + {252, "uuml;"}, + {253, "yacute;"}, + {254, "thorn;"}, + {255, "yuml;"}, + {338, "OElig;"}, + {339, "oelig;"}, + {352, "Scaron;"}, + {353, "scaron;"}, + {376, "Yuml;"}, + {402, "fnof;"}, + {710, "circ;"}, + {732, "tilde;"}, + {913, "Alpha;"}, + {914, "Beta;"}, + {915, "Gamma;"}, + {916, "Delta;"}, + {917, "Epsilon;"}, + {918, "Zeta;"}, + {919, "Eta;"}, + {920, "Theta;"}, + {921, "Iota;"}, + {922, "Kappa;"}, + {923, "Lambda;"}, + {924, "Mu;"}, + {925, "Nu;"}, + {926, "Xi;"}, + {927, "Omicron;"}, + {928, "Pi;"}, + {929, "Rho;"}, + {931, "Sigma;"}, + {932, "Tau;"}, + {933, "Upsilon;"}, + {934, "Phi;"}, + {935, "Chi;"}, + {936, "Psi;"}, + {937, "Omega;"}, + {945, "alpha;"}, + {946, "beta;"}, + {947, "gamma;"}, + {948, "delta;"}, + {949, "epsilon;"}, + {950, "zeta;"}, + {951, "eta;"}, + {952, "theta;"}, + {953, "iota;"}, + {954, "kappa;"}, + {955, "lambda;"}, + {956, "mu;"}, + {957, "nu;"}, + {958, "xi;"}, + {959, "omicron;"}, + {960, "pi;"}, + {961, "rho;"}, + {962, "sigmaf;"}, + {963, "sigma;"}, + {964, "tau;"}, + {965, "upsilon;"}, + {966, "phi;"}, + {967, "chi;"}, + {968, "psi;"}, + {969, "omega;"}, + {977, "thetasym;"}, + {978, "upsih;"}, + {982, "piv;"}, + {8194, "ensp;"}, + {8195, "emsp;"}, + {8201, "thinsp;"}, + {8204, "zwnj;"}, + {8205, "zwj;"}, + {8206, "lrm;"}, + {8207, "rlm;"}, + {8211, "ndash;"}, + {8212, "mdash;"}, + {8216, "lsquo;"}, + {8217, "rsquo;"}, + {8218, "sbquo;"}, + {8220, "ldquo;"}, + {8221, "rdquo;"}, + {8222, "bdquo;"}, + {8224, "dagger;"}, + {8225, "Dagger;"}, + {8226, "bull;"}, + {8230, "hellip;"}, + {8240, "permil;"}, + {8242, "prime;"}, + {8243, "Prime;"}, + {8249, "lsaquo;"}, + {8250, "rsaquo;"}, + {8254, "oline;"}, + {8260, "frasl;"}, + {8364, "euro;"}, + {8465, "image;"}, + {8472, "weierp;"}, + {8476, "real;"}, + {8482, "trade;"}, + {8501, "alefsym;"}, + {8592, "larr;"}, + {8593, "uarr;"}, + {8594, "rarr;"}, + {8595, "darr;"}, + {8596, "harr;"}, + {8629, "crarr;"}, + {8656, "lArr;"}, + {8657, "uArr;"}, + {8658, "rArr;"}, + {8659, "dArr;"}, + {8660, "hArr;"}, + {8704, "forall;"}, + {8706, "part;"}, + {8707, "exist;"}, + {8709, "empty;"}, + {8711, "nabla;"}, + {8712, "isin;"}, + {8713, "notin;"}, + {8715, "ni;"}, + {8719, "prod;"}, + {8721, "sum;"}, + {8722, "minus;"}, + {8727, "lowast;"}, + {8730, "radic;"}, + {8733, "prop;"}, + {8734, "infin;"}, + {8736, "ang;"}, + {8743, "and;"}, + {8744, "or;"}, + {8745, "cap;"}, + {8746, "cup;"}, + {8747, "int;"}, + {8756, "there4;"}, + {8764, "sim;"}, + {8773, "cong;"}, + {8776, "asymp;"}, + {8800, "ne;"}, + {8801, "equiv;"}, + {8804, "le;"}, + {8805, "ge;"}, + {8834, "sub;"}, + {8835, "sup;"}, + {8836, "nsub;"}, + {8838, "sube;"}, + {8839, "supe;"}, + {8853, "oplus;"}, + {8855, "otimes;"}, + {8869, "perp;"}, + {8901, "sdot;"}, + {8968, "lceil;"}, + {8969, "rceil;"}, + {8970, "lfloor;"}, + {8971, "rfloor;"}, + {9001, "lang;"}, + {9002, "rang;"}, + {9674, "loz;"}, + {9824, "spades;"}, + {9827, "clubs;"}, + {9829, "hearts;"}, + {9830, "diams;"}, + {0, NULL}, +}; + +static gchar * +unescape_string (const gchar * text) +{ + gint i; + GString *unescaped = g_string_new (NULL); + + while (*text) { + if (*text == '&') { + text++; + + /* unescape   and   */ + if (!g_ascii_strncasecmp (text, "nbsp", 4)) { + unescaped = g_string_append_unichar (unescaped, 160); + text += 4; + if (*text == ';') { + text++; + } + goto next; + } + + /* pass xml entities. these will be processed as pango markup */ + for (i = 0; XmlEntities[i].escaped; i++) { + gssize len = strlen (XmlEntities[i].escaped); + if (!g_ascii_strncasecmp (text, XmlEntities[i].escaped, len)) { + unescaped = g_string_append_c (unescaped, '&'); + unescaped = + g_string_append_len (unescaped, XmlEntities[i].escaped, len); + text += len; + goto next; + } + } + + /* convert html entities */ + for (i = 0; HtmlEntities[i].escaped; i++) { + gssize len = strlen (HtmlEntities[i].escaped); + if (!strncmp (text, HtmlEntities[i].escaped, len)) { + unescaped = + g_string_append_unichar (unescaped, HtmlEntities[i].unescaped); + text += len; + goto next; + } + } + + if (*text == '#') { + gboolean is_hex = FALSE; + gunichar l; + gchar *end = NULL; + + text++; + if (*text == 'x') { + is_hex = TRUE; + text++; + } + errno = 0; + if (is_hex) { + l = strtoul (text, &end, 16); + } else { + l = strtoul (text, &end, 10); + } + + if (text == end || errno != 0) { + /* error occured. pass it */ + goto next; + } + unescaped = g_string_append_unichar (unescaped, l); + text = end; + + if (*text == ';') { + text++; + } + goto next; + } + + /* escape & */ + unescaped = g_string_append (unescaped, "&"); + + next: + continue; + + } else if (g_ascii_isspace (*text)) { + unescaped = g_string_append_c (unescaped, ' '); + /* strip whitespace */ + do { + text++; + } while ((*text) && g_ascii_isspace (*text)); + } else { + unescaped = g_string_append_c (unescaped, *text); + text++; + } + } + + return g_string_free (unescaped, FALSE); +} + +static const gchar * +string_token (const gchar * string, const gchar * delimiter, gchar ** first) +{ + gchar *next = strstr (string, delimiter); + if (next) { + *first = g_strndup (string, next - string); + } else { + *first = g_strdup (string); + } + return next; +} + +static void +html_context_handle_element (HtmlContext * ctxt, + const gchar * string, gboolean must_close) +{ + gchar *name = NULL; + gint count = 0, i; + gchar **attrs; + const gchar *found, *next; +#ifdef SUBPARSE_MODIFICATION + const gchar *name_temp = NULL; + gint j = 0; +#endif + /* split element name and attributes */ + next = string_token (string, " ", &name); + + if (next) { + /* count attributes */ + found = next + 1; + while (TRUE) { + found = strchr (found, '='); + if (!found) + break; + found++; + count++; + } + } else { + count = 0; + } + + attrs = g_new0 (gchar *, (count + 1) * 2); + + for (i = 0; i < count; i += 2) { + gchar *attr_name = NULL, *attr_value = NULL; + gsize length; + +#ifdef SUBPARSE_MODIFICATION + /* sometimes count can unnecessarily be high value, because of unrequired "=" in subtitle file. + * In that case it should not crash */ + if (!next) + break; +#endif + + next = string_token (next + 1, "=", &attr_name); + +#ifdef SUBPARSE_MODIFICATION + /* sometimes count can unnecessarily be high value, because of unrequired "=" in subtitle file. + * In that case it should not crash */ + if (!next) + break; +#endif + + next = string_token (next + 1, " ", &attr_value); + + /* strip " or ' from attribute value */ + if (attr_value[0] == '"' || attr_value[0] == '\'') { + gchar *tmp = g_strdup (attr_value + 1); + g_free (attr_value); + attr_value = tmp; + } + + length = strlen (attr_value); + if (attr_value[length - 1] == '"' || attr_value[length - 1] == '\'') { + attr_value[length - 1] = '\0'; + } + + attrs[i] = attr_name; + attrs[i + 1] = attr_value; + } +#ifdef SUBPARSE_MODIFICATION + /* sometimes spaces can be there in between !-- and P + * that also we have to take care */ + if (!g_ascii_strcasecmp("!--", name)) { + gchar* tempchar = (gchar*)(string + 3); + while (*tempchar == ' ') { + tempchar++; + if (*tempchar == 'P' || *tempchar == 'p') { + *(name + 3) = *tempchar; + *(name + 4) = '\0'; + next = tempchar + 1; + break; + } + } + } + if (next && (!g_ascii_strcasecmp("!--P", name))) { + gint attrindex = 0; + count = 0; + /* count attributes */ + found = next + 1; + while (TRUE) { + found = (gchar*)strcasestr (found, "lang"); + if (!found) + break; + found++; + count++; + } + g_strfreev (attrs); + + attrs = g_new0 (gchar *, count * 2); + + for (i = 0; i < count; i++) { + gchar *attr_name = NULL, *attr_value = NULL; + + next = (gchar*)strcasestr (next, "lang:"); + attr_value = (gchar*)malloc (3); + next = next + 5; + strncpy (attr_value, next, 2); + attr_value[2] = '\0'; + GST_LOG ("Language value comes as %s", attr_value); + name_temp = next; + while (TRUE) { + if (*name_temp == '{') { + int character_count = 0; + + while (TRUE) { + name_temp--; + + if (*name_temp == '.') { + attr_name = (gchar*) malloc (character_count + 1); + break; + } + else if (*name_temp != ' ') + character_count++; + } + break; + } + name_temp--; + } + name_temp++; + for (j = 0; *(name_temp + j) != ' '; j++) { + attr_name[j] = *(name_temp + j); + } + attr_name[j] = '\0'; + attrs[attrindex++] = attr_name; + attrs[attrindex++] = attr_value; + } + } else { + count = 0; + } +#endif + ctxt->parser->start_element (ctxt, name, + (const gchar **) attrs, ctxt->user_data); + if (must_close) { + ctxt->parser->end_element (ctxt, name, ctxt->user_data); + } + g_strfreev (attrs); + g_free (name); +} + +static void +html_context_parse (HtmlContext * ctxt, gchar * text, gsize text_len) +{ + const gchar *next = NULL; + ctxt->buf = g_string_append_len (ctxt->buf, text, text_len); + next = ctxt->buf->str; + if (!next) { + GST_ERROR ("ctxt->buf->str is NULL"); + return; + } + while (TRUE) { + if (next[0] == '<') { + gchar *element = NULL; + /* find */ + if (!strchr (next, '>')) { + /* no tag end point. buffer will be process in next time */ + return; + } + + next = string_token (next, ">", &element); + next++; + if (g_str_has_suffix (next, "/")) { + /* handle */ + element[strlen (element) - 1] = '\0'; + html_context_handle_element (ctxt, element + 1, TRUE); + } else if (element[1] == '/') { + /* handle */ + ctxt->parser->end_element (ctxt, element + 2, ctxt->user_data); + } else { + /* handle */ + html_context_handle_element (ctxt, element + 1, FALSE); + } + g_free (element); + } else if (strchr (next, '<')) { + gchar *text = NULL; + gsize length; + next = string_token (next, "<", &text); + text = g_strstrip (text); + length = strlen (text); + ctxt->parser->text (ctxt, text, length, ctxt->user_data); + g_free (text); + + } else { + gchar *text = (gchar *) next; + gsize length; + text = g_strstrip (text); + length = strlen (text); + ctxt->parser->text (ctxt, text, length, ctxt->user_data); + ctxt->buf = g_string_assign (ctxt->buf, ""); + return; + } + } + + ctxt->buf = g_string_assign (ctxt->buf, next); +} + static gchar * has_tag (GString * str, const gchar tag) { @@ -116,26 +748,30 @@ sami_context_pop_state (GstSamiContext * sctx, char state) } static void -handle_start_sync (GstSamiContext * sctx, const xmlChar ** atts) +handle_start_sync (GstSamiContext * sctx, const gchar ** atts) { int i; sami_context_pop_state (sctx, CLEAR_TAG); if (atts != NULL) { for (i = 0; (atts[i] != NULL); i += 2) { - const xmlChar *key, *value; + const gchar *key, *value; key = atts[i]; value = atts[i + 1]; if (!value) continue; - if (!xmlStrncmp ((const xmlChar *) "start", key, 5)) { + if (!g_ascii_strcasecmp ("start", key)) { /* Only set a new start time if we don't have text pending */ if (sctx->resultbuf->len == 0) sctx->time1 = sctx->time2; sctx->time2 = atoi ((const char *) value) * GST_MSECOND; +#ifdef SUBPARSE_MODIFICATION + sctx->time3 = sctx->time2; +#endif + sctx->time2 = MAX (sctx->time2, sctx->time1); g_string_append (sctx->resultbuf, sctx->buf->str); sctx->has_result = (sctx->resultbuf->len != 0) ? TRUE : FALSE; g_string_truncate (sctx->buf, 0); @@ -145,7 +781,7 @@ handle_start_sync (GstSamiContext * sctx, const xmlChar ** atts) } static void -handle_start_font (GstSamiContext * sctx, const xmlChar ** atts) +handle_start_font (GstSamiContext * sctx, const gchar ** atts) { int i; @@ -153,53 +789,53 @@ handle_start_font (GstSamiContext * sctx, const xmlChar ** atts) if (atts != NULL) { g_string_append (sctx->buf, "= 0 && - ((xmlChar *) r == (value + 6) && len == 6)) { + ((gchar *) r == (value + 6) && len == 6)) { sharp = "#"; } } /* some colours can be found in many sami files, but X RGB database * doesn't contain a colour by this name, so map explicitly */ - if (!xmlStrncasecmp (value, (const xmlChar *) "aqua", len)) { - value = (const xmlChar *) "#00ffff"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "crimson", len)) { - value = (const xmlChar *) "#dc143c"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "fuchsia", len)) { - value = (const xmlChar *) "#ff00ff"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "indigo", len)) { - value = (const xmlChar *) "#4b0082"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "lime", len)) { - value = (const xmlChar *) "#00ff00"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "olive", len)) { - value = (const xmlChar *) "#808000"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "silver", len)) { - value = (const xmlChar *) "#c0c0c0"; - } else if (!xmlStrncasecmp (value, (const xmlChar *) "teal", len)) { - value = (const xmlChar *) "#008080"; + if (!g_ascii_strcasecmp ("aqua", value)) { + value = "#00ffff"; + } else if (!g_ascii_strcasecmp ("crimson", value)) { + value = "#dc143c"; + } else if (!g_ascii_strcasecmp ("fuchsia", value)) { + value = "#ff00ff"; + } else if (!g_ascii_strcasecmp ("indigo", value)) { + value = "#4b0082"; + } else if (!g_ascii_strcasecmp ("lime", value)) { + value = "#00ff00"; + } else if (!g_ascii_strcasecmp ("olive", value)) { + value = "#808000"; + } else if (!g_ascii_strcasecmp ("silver", value)) { + value = "#c0c0c0"; + } else if (!g_ascii_strcasecmp ("teal", value)) { + value = "#008080"; } g_string_append_printf (sctx->buf, " foreground=\"%s%s\"", sharp, value); - } else if (!xmlStrncasecmp ((const xmlChar *) "face", key, 4)) { + } else if (!g_ascii_strcasecmp ("face", key)) { g_string_append_printf (sctx->buf, " font_family=\"%s\"", value); } } @@ -208,49 +844,152 @@ handle_start_font (GstSamiContext * sctx, const xmlChar ** atts) } } +#ifdef SUBPARSE_MODIFICATION +static void +handle_p (GstSamiContext * sctx, const gchar ** atts) +{ + int i; + + if (atts != NULL) { + for (i = 0; (atts[i] != NULL); i += 2) { + const gchar *key, *value; + + key = atts[i]; + value = atts[i + 1]; + + if (sctx->current_language && value && strcmp(sctx->current_language, value) + && (sctx->time1 == sctx->time2)) + sctx->language_changed = TRUE; + + else if (!sctx->current_language) + sctx->current_language = (gchar*) malloc (128); + + if (key && !g_ascii_strcasecmp ("class", key) && value) { + strcpy (sctx->current_language, value); + if (sctx->desired_language == NULL && key) { + sctx->desired_language = g_strdup(value); + GST_LOG("no language list was found and desired lang was set to %s",sctx->desired_language); + } + } + if (sctx->language_changed) + { + sctx->time1 = 0; + sctx->time2 = sctx->time3; + sctx->language_changed = FALSE; + } + if (!value) + continue; + } + } +} + static void -start_sami_element (void *ctx, const xmlChar * name, const xmlChar ** atts) +handle_start_language_list (GstSamiContext * sctx, const gchar ** atts) { - GstSamiContext *sctx = (GstSamiContext *) ctx; + int i = 0; + int attrIndex = 0; + GstLangStruct *new = NULL; + GstLangStruct *temp = NULL; + + if (atts != NULL) { + if (g_list_length (sctx->lang_list)) { + GST_LOG ("We already got the language list"); + return; + } + for (i = 0; (atts[attrIndex] != NULL); i++) { + const gchar *key, *value; + + key = atts[attrIndex++]; + value = atts[attrIndex++]; + + GST_LOG ("Inside handle_start_language_list key: %s, value: %s", key, value); + + if (!value) + continue; + + new = g_new0 (GstLangStruct, 1); + new->language_code = (gchar*) malloc (strlen(value) + 1); + if (new->language_code && value) + strcpy (new->language_code, value); + new->language_key = (gchar*) malloc (strlen(key) + 1); + if (new->language_key && key) + strcpy (new->language_key, key); + sctx->lang_list = g_list_append (sctx->lang_list, new); + temp = g_list_nth_data (sctx->lang_list, i); + if (sctx->desired_language == NULL && key){ + sctx->desired_language = g_strdup(key); + } + + if (temp) + GST_LOG ("Inside handle_start_language_list of glist key: %s, value: %s", + temp->language_key, temp->language_code); + } + } +} +#endif + +static void +handle_start_element (HtmlContext * ctx, const gchar * name, + const char **atts, gpointer user_data) +{ + GstSamiContext *sctx = (GstSamiContext *) user_data; GST_LOG ("name:%s", name); - if (!xmlStrncmp ((const xmlChar *) "sync", name, 4)) { + if (!g_ascii_strcasecmp ("sync", name)) { handle_start_sync (sctx, atts); sctx->in_sync = TRUE; - } else if (!xmlStrncmp ((const xmlChar *) "font", name, 4)) { + } else if (!g_ascii_strcasecmp ("font", name)) { handle_start_font (sctx, atts); - } else if (!xmlStrncmp ((const xmlChar *) "ruby", name, 4)) { + } else if (!g_ascii_strcasecmp ("ruby", name)) { sami_context_push_state (sctx, RUBY_TAG); - } else if (!xmlStrncmp ((const xmlChar *) "br", name, 2)) { - g_string_append_c (sctx->buf, '\n'); + } else if (!g_ascii_strcasecmp ("br", name)) { +#ifdef SUBPARSE_MODIFICATION + if (sctx->current_language && sctx->desired_language && + !strcmp(sctx->current_language, sctx->desired_language)) +#endif + g_string_append_c (sctx->buf, '\n'); /* FIXME: support for furigana/ruby once implemented in pango */ - } else if (!xmlStrncmp ((const xmlChar *) "rt", name, 2)) { + } else if (!g_ascii_strcasecmp ("rt", name)) { if (has_tag (sctx->state, ITALIC_TAG)) { g_string_append (sctx->rubybuf, ""); } g_string_append (sctx->rubybuf, ""); sami_context_push_state (sctx, RT_TAG); - } else if (!xmlStrncmp ((const xmlChar *) "p", name, 1)) { - } else if (!xmlStrncmp ((const xmlChar *) "i", name, 1)) { - g_string_append (sctx->buf, ""); + } else if (!g_ascii_strcasecmp ("i", name)) { +#ifdef SUBPARSE_MODIFICATION + if (sctx->current_language && sctx->desired_language && + !strcmp(sctx->current_language, sctx->desired_language)) +#endif + g_string_append (sctx->buf, ""); sami_context_push_state (sctx, ITALIC_TAG); + } else if (!g_ascii_strcasecmp ("p", name)) { +#ifdef SUBPARSE_MODIFICATION + handle_p (sctx, atts); + } else if (!g_ascii_strcasecmp ("!--P", name)) { + handle_start_language_list (sctx, atts); +#endif } } static void -end_sami_element (void *ctx, const xmlChar * name) +handle_end_element (HtmlContext * ctx, const char *name, gpointer user_data) { - GstSamiContext *sctx = (GstSamiContext *) ctx; + GstSamiContext *sctx = (GstSamiContext *) user_data; GST_LOG ("name:%s", name); - if (!xmlStrncmp ((const xmlChar *) "sync", name, 4)) { + if (!g_ascii_strcasecmp ("sync", name)) { sctx->in_sync = FALSE; - } else if ((!xmlStrncmp ((const xmlChar *) "body", name, 4)) || - (!xmlStrncmp ((const xmlChar *) "sami", name, 4))) { + } else if ((!g_ascii_strcasecmp ("body", name)) || + (!g_ascii_strcasecmp ("sami", name))) { /* We will usually have one buffer left when the body is closed * as we need the next sync to actually send it */ + +#ifdef SUBPARSE_MODIFICATION + sctx->end_body = TRUE; +#endif + if (sctx->buf->len != 0) { /* Only set a new start time if we don't have text pending */ if (sctx->resultbuf->len == 0) @@ -261,128 +1000,109 @@ end_sami_element (void *ctx, const xmlChar * name) sctx->has_result = (sctx->resultbuf->len != 0) ? TRUE : FALSE; g_string_truncate (sctx->buf, 0); } - } else if (!xmlStrncmp ((const xmlChar *) "font", name, 4)) { + } else if (!g_ascii_strcasecmp ("font", name)) { sami_context_pop_state (sctx, SPAN_TAG); - } else if (!xmlStrncmp ((const xmlChar *) "ruby", name, 4)) { + } else if (!g_ascii_strcasecmp ("ruby", name)) { sami_context_pop_state (sctx, RUBY_TAG); - } else if (!xmlStrncmp ((const xmlChar *) "i", name, 1)) { + } else if (!g_ascii_strcasecmp ("i", name)) { sami_context_pop_state (sctx, ITALIC_TAG); } } static void -characters_sami (void *ctx, const xmlChar * ch, int len) +handle_text (HtmlContext * ctx, const gchar * text, gsize text_len, + gpointer user_data) { - GstSamiContext *sctx = (GstSamiContext *) ctx; - gchar *escaped; - gchar *tmp; - gint i; + GstSamiContext *sctx = (GstSamiContext *) user_data; /* Skip everything except content of the sync elements */ if (!sctx->in_sync) return; - - escaped = g_markup_escape_text ((const gchar *) ch, len); - g_strstrip (escaped); - - /* Remove double spaces forom the string as those are - * usually added by newlines and indention */ - tmp = escaped; - for (i = 0; i <= strlen (escaped); i++) { - escaped[i] = *tmp; - if (*tmp != ' ') { - tmp++; - continue; - } - while (*tmp == ' ') - tmp++; - } - +#ifdef SUBPARSE_MODIFICATION + if (has_tag (sctx->state, RT_TAG) && (sctx->current_language && sctx->desired_language && + !strcmp(sctx->current_language, sctx->desired_language))) { +#else if (has_tag (sctx->state, RT_TAG)) { +#endif g_string_append_c (sctx->rubybuf, ' '); - g_string_append (sctx->rubybuf, escaped); + g_string_append (sctx->rubybuf, text); g_string_append_c (sctx->rubybuf, ' '); } else { - g_string_append (sctx->buf, escaped); +#ifdef SUBPARSE_MODIFICATION + if (sctx->current_language && sctx->desired_language && + !strcmp(sctx->current_language, sctx->desired_language)) +#endif + g_string_append (sctx->buf, text); } - g_free (escaped); } -static xmlSAXHandler samiSAXHandlerStruct = { - NULL, /* internalSubset */ - NULL, /* isStandalone */ - NULL, /* hasInternalSubset */ - NULL, /* hasExternalSubset */ - NULL, /* resolveEntity */ - NULL, /* getEntity */ - NULL, /* entityDecl */ - NULL, /* notationDecl */ - NULL, /* attributeDecl */ - NULL, /* elementDecl */ - NULL, /* unparsedEntityDecl */ - NULL, /* setDocumentLocator */ - NULL, /* startDocument */ - NULL, /* endDocument */ - start_sami_element, /* startElement */ - end_sami_element, /* endElement */ - NULL, /* reference */ - characters_sami, /* characters */ - NULL, /* ignorableWhitespace */ - NULL, /* processingInstruction */ - NULL, /* comment */ - NULL, /* xmlParserWarning */ - NULL, /* xmlParserError */ - NULL, /* xmlParserError */ - NULL, /* getParameterEntity */ - NULL, /* cdataBlock */ - NULL, /* externalSubset */ - 1, /* initialized */ - NULL, /* private */ - NULL, /* startElementNsSAX2Func */ - NULL, /* endElementNsSAX2Func */ - NULL /* xmlStructuredErrorFunc */ +static HtmlParser samiParser = { + handle_start_element, /* start_element */ + handle_end_element, /* end_element */ + handle_text, /* text */ }; -static xmlSAXHandlerPtr samiSAXHandler = &samiSAXHandlerStruct; - void sami_context_init (ParserState * state) { GstSamiContext *context; g_assert (state->user_data == NULL); - state->user_data = (gpointer) g_new0 (GstSamiContext, 1); - context = (GstSamiContext *) state->user_data; - context->htmlctxt = htmlCreatePushParserCtxt (samiSAXHandler, context, - "", 0, NULL, XML_CHAR_ENCODING_UTF8); + context = g_new0 (GstSamiContext, 1); + + context->htmlctxt = html_context_new (&samiParser, context); context->buf = g_string_new (""); context->rubybuf = g_string_new (""); context->resultbuf = g_string_new (""); context->state = g_string_new (""); +#ifdef SUBPARSE_MODIFICATION + context->current_language = NULL; + context->desired_language = NULL; + context->lang_list = NULL; + context->language_changed = FALSE; + context->end_body = FALSE; +#endif + state->user_data = context; } void sami_context_deinit (ParserState * state) { GstSamiContext *context = (GstSamiContext *) state->user_data; - +#ifdef SUBPARSE_MODIFICATION + GstLangStruct *temp = NULL; + int i = 0; +#endif if (context) { - htmlParserCtxtPtr htmlctxt = context->htmlctxt; - - /* destroy sax context */ - htmlDocPtr doc; - - htmlParseChunk (htmlctxt, "", 0, 1); - doc = htmlctxt->myDoc; - htmlFreeParserCtxt (htmlctxt); + html_context_free (context->htmlctxt); context->htmlctxt = NULL; - if (doc) - xmlFreeDoc (doc); g_string_free (context->buf, TRUE); g_string_free (context->rubybuf, TRUE); g_string_free (context->resultbuf, TRUE); g_string_free (context->state, TRUE); +#ifdef SUBPARSE_MODIFICATION + if (context->lang_list) { + while ((temp = g_list_nth_data (context->lang_list, i))) { + if (temp->language_code) + free (temp->language_code); + temp->language_code = NULL; + if (temp->language_key) + free (temp->language_key); + temp->language_key = NULL; + g_free (temp); + i++; + } + g_list_free (context->lang_list); + } + context->lang_list = NULL; + + if (context->current_language) + free (context->current_language); + context->current_language = NULL; + + context->desired_language = NULL; +#endif g_free (context); state->user_data = NULL; } @@ -405,70 +1125,239 @@ sami_context_reset (ParserState * state) } } -static gchar * -fix_invalid_entities (const gchar * line) +#ifdef SUBPARSE_MODIFICATION +void +sami_context_change_language (ParserState * state) { - const gchar *cp, *pp; /* current pointer, previous pointer */ - gssize size; - GString *ret = g_string_new (NULL); - - pp = line; - cp = strchr (line, '&'); - while (cp) { - size = cp - pp; - ret = g_string_append_len (ret, pp, size); - cp++; - if (g_ascii_strncasecmp (cp, "nbsp;", 5) - && (!g_ascii_strncasecmp (cp, "nbsp", 4))) { - /* translate " " to " " */ - ret = g_string_append_len (ret, " ", 6); - cp += 4; - } else if (g_ascii_strncasecmp (cp, "quot;", 5) - && g_ascii_strncasecmp (cp, "amp;", 4) - && g_ascii_strncasecmp (cp, "apos;", 5) - && g_ascii_strncasecmp (cp, "lt;", 3) - && g_ascii_strncasecmp (cp, "gt;", 3) - && g_ascii_strncasecmp (cp, "nbsp;", 5) - && cp[0] != '#') { - /* translate "&" to "&" */ - ret = g_string_append_len (ret, "&", 5); - } else { - /* do not translate */ - ret = g_string_append_c (ret, '&'); + GstSamiContext *context = (GstSamiContext *) state->user_data; + GST_LOG ("**********desired language was %s**************", context->desired_language); + free (context->desired_language); + if(state->current_language) { + context->desired_language = state->current_language; + } else { + context->desired_language = state->msl_language; + } + GST_LOG ("desired language changed to %s", context->desired_language); +} + +gchar * +sami_convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding, + gsize * consumed, GError ** err, GstSubParse * self) +{ + gchar *ret = NULL; + + /* The char cast is necessary in glib < 2.24 */ + ret = + g_convert_with_fallback (str, len, "UTF-8", encoding, (char *) "*", + consumed, NULL, err); + + if (ret == NULL) + { + GST_DEBUG_OBJECT (self, "g_convert_with_fallback returns NULL"); + return ret; + } + + /* + 3 to skip UTF-8 BOM if it was added */ + len = strlen (ret); + if (len >= 3 && (guint8) ret[0] == 0xEF && (guint8) ret[1] == 0xBB + && (guint8) ret[2] == 0xBF) + g_memmove (ret, ret + 3, len + 1 - 3); + + return ret; +} + +gboolean +sami_validate_langlist_body(GList * lang_list, GstSubParse * self){ + gchar * file_path_type = NULL; + gchar * file_path = NULL; + gchar line[1024]; + FILE * fp = NULL; + guint i = 0, found_count = 0; + const guint list_len = g_list_length(lang_list); + gboolean counter[MAX_LANGUAGE]; + struct LangStruct + { + gchar *language_code; + gchar *language_key; + } * lang; + + GstQuery *cquery; + GstStructure *structure; + const GValue *value; + structure = gst_structure_new ("FileSrcURI", + "file-uri", G_TYPE_STRING, NULL, NULL); + + cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure); + + if (!gst_pad_peer_query (self->sinkpad, cquery)) + { + GST_DEBUG_OBJECT (self, "failed to query SMI file path"); + gst_query_unref (cquery); + return FALSE; + } + structure = gst_query_get_structure (cquery); + value = gst_structure_get_value (structure, "file-uri"); + file_path = g_strdup (g_value_get_string (value)); + + if (file_path == NULL){ + GST_DEBUG_OBJECT (self, "could not parse the SMI file path"); + gst_query_unref (cquery); + return FALSE; + } + gst_query_unref (cquery); + + GST_INFO_OBJECT (self, "file path comes as %s", file_path); + + file_path_type = g_strndup ((gchar *) file_path, 4); + GST_INFO_OBJECT (self, "received file path by query = %s,%s", file_path,file_path_type); + if (!g_strcmp0(file_path_type, "file")){ + file_path += 7; + GST_INFO_OBJECT (self, "file path comes as %s", file_path); + + fp = fopen (file_path, "r"); + if (!fp){ + GST_DEBUG_OBJECT (self, "failed to open file"); + return FALSE; + } + + for(i=0;idetected_encoding,self->encoding); + if (self->detected_encoding && strcmp (self->detected_encoding, "UTF-8") && conversion){ + result = sami_convert_to_utf8 (line, charCount, self->detected_encoding, consumed, &err, self); + } + if(result == NULL) { + result = line; + conversion = FALSE; + } + con_temp = g_utf8_strdown (result,strlen(result)); + temp = con_temp; + while(con_temp) { + con_temp = g_strstr_len(con_temp, strlen(con_temp),"class="); + if(con_temp) { + temp1 = g_strstr_len(con_temp+1, strlen(con_temp),"class="); + } + if(temp1 && con_temp){ + gap = strlen(con_temp)-strlen(temp1); + }else if(con_temp) { + gap = strlen(con_temp); + } else { + continue; + } + if(con_temp){ + for(i=0;ilanguage_key); + con_temp_lang = g_utf8_strdown (temp_lang,strlen(temp_lang)); + if(g_strstr_len(con_temp,gap,con_temp_lang)){ + found_count++; + counter[i]=TRUE; + GST_INFO_OBJECT (self, " valid Language in list : [%s]", lang->language_key); + con_temp=con_temp+1; + } + g_free(temp_lang); + g_free(con_temp_lang); + } + } + } + } + if(conversion) + g_free (result); + if(temp) + g_free(temp); + + } + + if(found_count < list_len){ + for(i=0;iuser_data; - fixed_line = fix_invalid_entities (line); - htmlParseChunk (context->htmlctxt, fixed_line, strlen (fixed_line), 0); - g_free (fixed_line); + gchar *unescaped = unescape_string (line); + html_context_parse (context->htmlctxt, (gchar *) unescaped, + strlen (unescaped)); +#ifdef SUBPARSE_MODIFICATION + if (context->lang_list) + state->language_list = context->lang_list; - if (context->has_result) { - gchar *r; + if (context->desired_language) + state->current_language = context->desired_language; +#endif + g_free (unescaped); +#ifdef SUBPARSE_MODIFICATION + if (context->desired_language && context->current_language) { + if ((!strcmp(context->current_language, context->desired_language)) || context->end_body) { +#endif + if (context->has_result) { + if (context->rubybuf->len) { + context->rubybuf = g_string_append_c (context->rubybuf, '\n'); + g_string_prepend (context->resultbuf, context->rubybuf->str); + context->rubybuf = g_string_truncate (context->rubybuf, 0); + } - if (context->rubybuf->len) { - context->rubybuf = g_string_append_c (context->rubybuf, '\n'); - g_string_prepend (context->resultbuf, context->rubybuf->str); - context->rubybuf = g_string_truncate (context->rubybuf, 0); + ret = g_string_free (context->resultbuf, FALSE); + context->resultbuf = g_string_new (""); + state->start_time = context->time1; + state->duration = context->time2 - context->time1; + context->has_result = FALSE; + } +#ifdef SUBPARSE_MODIFICATION + context->end_body = FALSE; } + } + /* Check our segment start/stop */ + in_seg = gst_segment_clip (state->segment, GST_FORMAT_TIME, + state->start_time, state->start_time + state->duration, &clip_start, + &clip_stop); - r = g_string_free (context->resultbuf, FALSE); - context->resultbuf = g_string_new (""); - state->start_time = context->time1; - state->duration = context->time2 - context->time1; - context->has_result = FALSE; - return r; + /* No need to send that text if it's out of segment */ + if (in_seg) { + state->start_time = clip_start; + state->duration = clip_stop - clip_start; + } else { + return NULL; } - return NULL; +#endif + return ret; } diff --git a/gst/subparse/samiparse.h b/gst/subparse/samiparse.h old mode 100644 new mode 100755 index a45de01..77ea9fe --- a/gst/subparse/samiparse.h +++ b/gst/subparse/samiparse.h @@ -13,8 +13,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifndef _SAMI_PARSE_H_ @@ -31,6 +31,12 @@ void sami_context_init (ParserState * state); void sami_context_deinit (ParserState * state); void sami_context_reset (ParserState * state); +#ifdef SUBPARSE_MODIFICATION +void sami_context_change_language (ParserState * state); +gboolean sami_validate_langlist_body(GList * lang_list, GstSubParse * self); +gchar * sami_convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding, + gsize * consumed, GError ** err, GstSubParse * self); +#endif G_END_DECLS diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c old mode 100644 new mode 100755 index 63a6d55..7402c50 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -477,6 +477,67 @@ hls_type_find (GstTypeFind * tf, gpointer unused) } \ } +#define XML_INC_BUFFER_DATA { \ + pos++; \ + if (pos >= length) { \ + return FALSE; \ + } else { \ + data++; \ + } \ +} + +static gboolean +xml_check_first_element_from_data (const guint8 * data, guint length, + const gchar * element, guint elen, gboolean strict) +{ + gboolean got_xmldec; + guint pos = 0; + + g_return_val_if_fail (data != NULL, FALSE); + + if (length <= 5) + return FALSE; + + /* look for the XMLDec + * see XML spec 2.8, Prolog and Document Type Declaration + * http://www.w3.org/TR/2004/REC-xml-20040204/#sec-prolog-dtd */ + got_xmldec = (memcmp (data, "= length) + return FALSE; + pos += 5; + data += 5; + } + + /* look for the first element, it has to be the requested element. Bail + * out if it is not within the first 4kB. */ + while (data && pos < MIN (4096, length)) { + while (*data != '<' && pos < MIN (4096, length)) { + XML_INC_BUFFER_DATA; + } + + XML_INC_BUFFER_DATA; + if (!g_ascii_isalpha (*data)) { + /* if not alphabetic, it's a PI or an element / attribute declaration + * like = length) + return FALSE; + return (data && element && strncmp ((char *) data, element, elen) == 0); + } + + return FALSE; +} + static gboolean xml_check_first_element (GstTypeFind * tf, const gchar * element, guint elen, gboolean strict) @@ -584,6 +645,71 @@ smil_type_find (GstTypeFind * tf, gpointer unused) } } +#ifdef GST_EXT_SS_TYPE +/*** application/x-ss [Microsoft's Smooth Streaming]***********************************/ + +static GstStaticCaps ss_caps = GST_STATIC_CAPS ("application/x-ss"); + +#define SS_CAPS (gst_static_caps_get(&ss_caps)) +static void +ss_type_find (GstTypeFind * tf, gpointer unused) +{ + + if (xml_check_first_element (tf, "SmoothStreamingMedia", 20, TRUE)) { + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SS_CAPS); + } else { + const guint8 *data; + gboolean utf16_le, utf16_be; + const gchar *convert_from = NULL; + guint8 *converted_data; + + /* try detecting the charset */ + data = gst_type_find_peek (tf, 0, 2); + + if (data == NULL) + return; + + /* look for a possible BOM */ + utf16_le = data[0] == 0xFF && data[1] == 0xFE; + utf16_be = data[0] == 0xFE && data[1] == 0xFF; + if (utf16_le) { + convert_from = "UTF-16LE"; + } else if (utf16_be) { + convert_from = "UTF-16BE"; + } + + if (convert_from) { + gsize new_size = 0; + guint length = gst_type_find_get_length (tf); + + /* try a default that should be enough */ + if (length == 0) + length = 512; + data = gst_type_find_peek (tf, 0, length); + + if (data) { + /* skip the BOM */ + data += 2; + length -= 2; + + converted_data = + (guint8 *) g_convert ((gchar *) data, length, "UTF-8", convert_from, + NULL, &new_size, NULL); + if (converted_data) { + if (xml_check_first_element_from_data (converted_data, new_size, + "SmoothStreamingMedia", 20, TRUE)) + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, + SS_CAPS); + + g_free (converted_data); + } + } + } + } + +} +#endif + /*** text/html ***/ static GstStaticCaps html_caps = GST_STATIC_CAPS ("text/html"); @@ -980,6 +1106,45 @@ aac_type_find (GstTypeFind * tf, gpointer unused) } gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, caps); +#ifdef GST_EXT_TYPEFIND_ENHANCEMENT + /* find more aac sync to select correctly */ + + /* check if there's a third ADTS frame */ + len = ((c.data[3] & 0x03) << 11) | (c.data[4] << 3) | ((c.data[5] & 0xe0) >> 5); + if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) { + GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); + goto next; + } + snc = GST_READ_UINT16_BE (c.data + len); + if ((snc & 0xfff6) == 0xfff0) { + gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY + 5, caps); /* 85% */ + GST_DEBUG ("Find 3rd Sync..probability is %u ", GST_TYPE_FIND_LIKELY + 5); + } + + /* check if there's a fourth ADTS frame */ + len = ((c.data[3] & 0x03) << 11) | (c.data[4] << 3) | ((c.data[5] & 0xe0) >> 5); + if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) { + GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); + goto next; + } + snc = GST_READ_UINT16_BE (c.data + len); + if ((snc & 0xfff6) == 0xfff0) { + gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY + 10, caps); /* 90% */ + GST_DEBUG ("Find 4th Sync..probability is %u ", GST_TYPE_FIND_LIKELY + 10); + } + + /* check if there's a fifth(last) ADTS frame */ + len = ((c.data[3] & 0x03) << 11) | (c.data[4] << 3) | ((c.data[5] & 0xe0) >> 5); + if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) { + GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); + goto next; + } + snc = GST_READ_UINT16_BE (c.data + len); + if ((snc & 0xfff6) == 0xfff0) { + gst_type_find_suggest (tf, GST_TYPE_FIND_NEARLY_CERTAIN, caps); /* 99% */ + GST_DEBUG ("Find 5th Sync..probability is %u ", GST_TYPE_FIND_NEARLY_CERTAIN); + } +#endif gst_caps_unref (caps); break; } @@ -1831,7 +1996,7 @@ static GstStaticCaps multipart_caps = GST_STATIC_CAPS ("multipart/x-mixed-replace"); #define MULTIPART_CAPS gst_static_caps_get(&multipart_caps) -/* multipart/x-mixed replace is: +/* multipart/x-mixed replace is: * --[\r]\n * [\r]\nContent-type:[\r]\n */ static void @@ -1888,7 +2053,7 @@ static GstStaticCaps mpeg_sys_caps = GST_STATIC_CAPS ("video/mpeg, " #define IS_MPEG_PES_HEADER(data) (IS_MPEG_HEADER (data) && \ IS_MPEG_PES_CODE (((guint8 *)(data))[3])) -#define MPEG2_MAX_PROBE_LENGTH (128 * 1024) /* 128kB should be 64 packs of the +#define MPEG2_MAX_PROBE_LENGTH (128 * 1024) /* 128kB should be 64 packs of the * most common 2kB pack size. */ #define MPEG2_MIN_SYS_HEADERS 2 @@ -2103,7 +2268,7 @@ mpeg_sys_type_find (GstTypeFind * tf, gpointer unused) } /* If we at least saw MIN headers, and *some* were pes headers (pack headers - * are optional in an mpeg system stream) then return a lower-probability + * are optional in an mpeg system stream) then return a lower-probability * result */ if (pes_headers > 0 && (pack_headers + pes_headers) > MPEG2_MIN_SYS_HEADERS) goto suggest; @@ -2179,7 +2344,7 @@ mpeg_ts_probe_headers (GstTypeFind * tf, guint64 offset, gint packet_size) static void mpeg_ts_type_find (GstTypeFind * tf, gpointer unused) { - /* TS packet sizes to test: normal, DVHS packet size and + /* TS packet sizes to test: normal, DVHS packet size and * FEC with 16 or 20 byte codes packet size. */ const gint pack_sizes[] = { 188, 192, 204, 208 }; const guint8 *data = NULL; @@ -2208,7 +2373,7 @@ mpeg_ts_type_find (GstTypeFind * tf, gpointer unused) if (found >= GST_MPEGTS_TYPEFIND_MIN_HEADERS) { gint probability; - /* found at least 4 headers. 10 headers = MAXIMUM probability. + /* found at least 4 headers. 10 headers = MAXIMUM probability. * Arbitrarily, I assigned 10% probability for each header we * found, 40% -> 100% */ probability = MIN (10 * found, GST_TYPE_FIND_MAXIMUM); @@ -2443,7 +2608,7 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) { DataScanCtx c = { 0, NULL, 0 }; - /* Stream consists of: a series of sync codes (00 00 00 01) followed + /* Stream consists of: a series of sync codes (00 00 00 01) followed * by NALs */ int nut, ref; @@ -2708,6 +2873,14 @@ q3gp_type_find_get_profile (const guint8 * data) return "general"; case GST_MAKE_FOURCC ('3', 'g', 'p', 0): return "basic"; +#ifdef GST_EXT_MIME_TYPES /* add extended keyword for differentiating */ + case GST_MAKE_FOURCC ('3', 'g', '2', 0): + return "extended"; + case GST_MAKE_FOURCC ('i', 's', 'm', 0): { + g_print ("fragment file format...\n\n"); + return "fragmented"; + } +#endif case GST_MAKE_FOURCC ('3', 'g', 's', 0): return "streaming-server"; case GST_MAKE_FOURCC ('3', 'g', 'r', 0): @@ -2715,6 +2888,14 @@ q3gp_type_find_get_profile (const guint8 * data) default: break; } + +#ifdef GST_EXT_MIME_TYPES + if (GST_MAKE_FOURCC (data[0], data[1], data[2], data[3]) == GST_MAKE_FOURCC ('p', 'i', 'f', 'f')) { + g_print ("piff fragmented...\n\n"); + return "fragmented"; + } +#endif + return NULL; } @@ -2821,7 +3002,8 @@ qt_type_find (GstTypeFind * tf, gpointer unused) if (STRNCMP (&data[4], "ftypisom", 8) == 0 || STRNCMP (&data[4], "ftypavc1", 8) == 0 || - STRNCMP (&data[4], "ftypmp42", 8) == 0) { + STRNCMP (&data[4], "ftypmp42", 8) == 0 || + STRNCMP (&data[4], "ftypwmf ", 8) == 0) { tip = GST_TYPE_FIND_MAXIMUM; variant = "iso"; break; @@ -2841,9 +3023,8 @@ qt_type_find (GstTypeFind * tf, gpointer unused) } } /* other box/atom types, apparently quicktime specific */ - else if (STRNCMP (&data[4], "pnot", 4) == 0 || - STRNCMP (&data[4], "PICT", 4) == 0 || - STRNCMP (&data[4], "wide", 4) == 0 || + else if (STRNCMP (&data[4], "PICT", 4) == 0 || + STRNCMP (&data[4], "wide", 4) == 0 || STRNCMP (&data[4], "prfl", 4) == 0) { tip = GST_TYPE_FIND_MAXIMUM; break; @@ -2863,7 +3044,8 @@ qt_type_find (GstTypeFind * tf, gpointer unused) if (STRNCMP (&data[4], "isom", 4) == 0 || STRNCMP (&data[4], "avc1", 4) == 0 || STRNCMP (&data[4], "mp41", 4) == 0 || - STRNCMP (&data[4], "mp42", 4) == 0) { + STRNCMP (&data[4], "mp42", 4) == 0 || + STRNCMP (&data[4], "wmf ", 4) == 0) { tip = GST_TYPE_FIND_MAXIMUM; variant = "iso"; goto done; @@ -4476,6 +4658,9 @@ plugin_init (GstPlugin * plugin) static const gchar *ape_exts[] = { "ape", NULL }; static const gchar *uri_exts[] = { "ram", NULL }; static const gchar *hls_exts[] = { "m3u8", NULL }; +#ifdef GST_EXT_SS_TYPE + static const gchar *ss_exts[] = { "manifest", NULL }; +#endif static const gchar *sdp_exts[] = { "sdp", NULL }; static const gchar *smil_exts[] = { "smil", NULL }; static const gchar *html_exts[] = { "htm", "html", NULL }; @@ -4503,7 +4688,7 @@ plugin_init (GstPlugin * plugin) static const gchar *zip_exts[] = { "zip", NULL }; static const gchar *compress_exts[] = { "Z", NULL }; static const gchar *m4a_exts[] = { "m4a", NULL }; - static const gchar *q3gp_exts[] = { "3gp", NULL }; + static const gchar *q3gp_exts[] = { "3gp", "ismv", "isma", NULL }; static const gchar *aac_exts[] = { "aac", "adts", "adif", "loas", NULL }; static const gchar *spc_exts[] = { "spc", NULL }; static const gchar *wavpack_exts[] = { "wv", "wvp", NULL }; @@ -4563,12 +4748,13 @@ plugin_init (GstPlugin * plugin) #ifndef GST_EXT_MIME_TYPES TYPE_FIND_REGISTER_RIFF (plugin, "audio/qcelp", GST_RANK_PRIMARY, qcp_exts, "QLCM"); - TYPE_FIND_REGISTER_RIFF (plugin, "video/x-cdxa", GST_RANK_PRIMARY, - cdxa_exts, "CDXA"); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-vcd", GST_RANK_PRIMARY, cdxa_exts, "\000\377\377\377\377\377\377\377\377\377\377\000", 12, GST_TYPE_FIND_MAXIMUM); #endif + TYPE_FIND_REGISTER_RIFF (plugin, "video/x-cdxa", GST_RANK_PRIMARY, + cdxa_exts, "CDXA"); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-imelody", GST_RANK_PRIMARY, imelody_exts, "BEGIN:IMELODY", 13, GST_TYPE_FIND_MAXIMUM); #if 0 @@ -4612,9 +4798,9 @@ plugin_init (GstPlugin * plugin) #ifndef GST_EXT_MIME_TYPES TYPE_FIND_REGISTER (plugin, "audio/x-gsm", GST_RANK_PRIMARY, NULL, gsm_exts, GSM_CAPS, NULL, NULL); +#endif TYPE_FIND_REGISTER (plugin, "video/mpeg-sys", GST_RANK_PRIMARY, mpeg_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL); -#endif TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY, mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, @@ -4672,12 +4858,16 @@ plugin_init (GstPlugin * plugin) hls_type_find, hls_exts, HLS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/sdp", GST_RANK_SECONDARY, sdp_type_find, sdp_exts, SDP_CAPS, NULL, NULL); +#ifdef GST_EXT_SS_TYPE + TYPE_FIND_REGISTER (plugin, "application/x-ss", GST_RANK_PRIMARY, + ss_type_find, ss_exts, SS_CAPS, NULL, NULL); +#endif #ifndef GST_EXT_MIME_TYPES TYPE_FIND_REGISTER (plugin, "application/smil", GST_RANK_SECONDARY, smil_type_find, smil_exts, SMIL_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/xml", GST_RANK_MARGINAL, xml_type_find, xml_exts, GENERIC_XML_CAPS, NULL, NULL); -#endif +#endif TYPE_FIND_REGISTER_RIFF (plugin, "audio/x-wav", GST_RANK_PRIMARY, wav_exts, "WAVE"); #ifndef GST_EXT_MIME_TYPES @@ -4701,7 +4891,7 @@ plugin_init (GstPlugin * plugin) shn_type_find, shn_exts, SHN_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-ape", GST_RANK_SECONDARY, ape_type_find, ape_exts, APE_CAPS, NULL, NULL); -#endif +#endif TYPE_FIND_REGISTER (plugin, "image/jpeg", GST_RANK_PRIMARY + 15, jpeg_type_find, jpeg_exts, JPEG_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "image/gif", GST_RANK_PRIMARY, diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index e4ba16c..1633302 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -608,14 +608,38 @@ gst_video_rate_flush_prev (GstVideoRate * videorate, gboolean duplicate) GstFlowReturn res; GstBuffer *outbuf; GstClockTime push_ts; - +#ifdef VIDEORATE_MODIFICATION + GstStructure *structure; + guint32 format; + GstCaps *buf_caps; +#endif if (!videorate->prevbuf) goto eos_before_buffers; /* make sure we can write to the metadata */ - outbuf = gst_buffer_make_metadata_writable - (gst_buffer_ref (videorate->prevbuf)); - +#ifdef VIDEORATE_MODIFICATION + buf_caps = gst_buffer_get_caps (videorate->prevbuf); + if(!buf_caps) { + GST_ERROR("not able to get the caps"); + return GST_FLOW_ERROR; + } + structure = gst_caps_get_structure (buf_caps, 0); + if(!structure) { + GST_ERROR("not able to get the structure"); + return GST_FLOW_ERROR; + } + if (!gst_structure_get_fourcc (structure, "format", &format)) { + GST_ERROR ("can not get format in gst structure"); + } + if(format== GST_MAKE_FOURCC('S', 'T', '1', '2') || format== GST_MAKE_FOURCC('S', 'N', '1', '2')) { + GST_ERROR("setting the format_transcode as TRUE"); + outbuf=videorate->prevbuf; + gst_caps_unref(buf_caps); + } else { + outbuf = gst_buffer_make_metadata_writable + (gst_buffer_ref (videorate->prevbuf)); + } +#endif GST_BUFFER_OFFSET (outbuf) = videorate->out; GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1; diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h index 772548c..50c8e56 100644 --- a/gst/videorate/gstvideorate.h +++ b/gst/videorate/gstvideorate.h @@ -19,7 +19,7 @@ #ifndef __GST_VIDEO_RATE_H__ #define __GST_VIDEO_RATE_H__ - +#define VIDEORATE_MODIFICATION #include #include diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index 1f40f62..6272a0d 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -136,8 +136,15 @@ enum "rate = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ "width = (int) 32, " \ - "depth = (int) 32, " \ - "signed = (bool) TRUE" + "depth = (int) 32, " \ + "signed = (bool) TRUE;" \ + "audio/x-raw-int, " \ + "channels = (int) [ 1, MAX ], " \ + "rate = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 32, " \ + "depth = (int) 24, " \ + "signed = (bool) TRUE" static void gst_volume_interface_init (GstImplementsInterfaceClass * klass); static void gst_volume_mixer_init (GstMixerClass * iface); diff --git a/packaging/gst-plugins-base.spec b/packaging/gst-plugins-base.spec old mode 100644 new mode 100755 index 5ae42b5..9762b70 --- a/packaging/gst-plugins-base.spec +++ b/packaging/gst-plugins-base.spec @@ -1,12 +1,13 @@ Name: gst-plugins-base Summary: GStreamer streaming media framework base plug-ins -Version: 0.10.36 -Release: 7 +Version: 0.10.37 +Release: 171 Group: Applications/Multimedia -License: LGPLv2+ +License: LGPL-2.0+ Source0: %{name}-%{version}.tar.gz #Patch0: Samsung-feature-bugs.patch Requires(post): /sbin/ldconfig +Requires(post): /usr/bin/vconftool Requires(postun): /sbin/ldconfig BuildRequires: pkgconfig(ogg) BuildRequires: pkgconfig(theora) @@ -17,8 +18,15 @@ BuildRequires: pkgconfig(alsa) BuildRequires: pkgconfig(gstreamer-0.10) BuildRequires: pkgconfig(gstreamer-base-0.10) BuildRequires: pkgconfig(xv) -BuildRequires: pkgconfig(pango) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(dri2proto) +BuildRequires: pkgconfig(libdri2) +BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(utilX) BuildRequires: intltool +#BuildRequires: libsavscodec-neon-devel +BuildRequires: pkgconfig(vconf) %description @@ -54,10 +62,18 @@ Separate sub-package contaning helper applications of gstreamer base plugins. %build %autogen --noconfigure +#Add -DSAMSUNG_WFD_SPEC to enable RTP over TCP streaming support export CFLAGS+=" -Wall -g -fPIC\ -DGST_EXT_XV_ENHANCEMENT\ + -DSAMSUNG_WFD_SPEC\ + -DGST_EXT_SS_TYPE\ -DGST_EXT_LINK_FIMCCONVERT\ - -DGST_EXT_MIME_TYPES" + -DGST_EXT_MIME_TYPES\ + -DGST_EXT_ENABLE_SMI\ + -DGST_EXT_TYPEFIND_ENHANCEMENT\ + -DGST_EXT_TIME_ANALYSIS\ + -DGST_EXT_DECODEBIN2_QUEUESIZE\ + -DGST_EXT_DECODEBIN2_MODIFICATION" %configure --prefix=/usr\ --disable-static\ @@ -75,7 +91,8 @@ export CFLAGS+=" -Wall -g -fPIC\ --disable-gcov\ --disable-gtk-doc\ --disable-debug\ - --with-audioresample-format=int + --with-audioresample-format=int\ + --disable-gst_v4l make %{?jobs:-j%jobs} @@ -86,12 +103,15 @@ rm -rf %{buildroot} rm -rf %{buildroot}/tmp/dump -%post -p /sbin/ldconfig +%post +/sbin/ldconfig +/usr/bin/vconftool set -t int memory/Player/XvStateInfo 0 -g 29 -f -i -s system::vconf_multimedia %postun -p /sbin/ldconfig %files +%manifest gst-plugins-base.manifest %defattr(-,root,root,-) #%doc COPYING # libraries @@ -123,7 +143,6 @@ rm -rf %{buildroot}/tmp/dump %{_libdir}/gstreamer-0.10/libgstvideorate.so %{_libdir}/gstreamer-0.10/libgstvideoscale.so %{_libdir}/gstreamer-0.10/libgsttcp.so -%{_libdir}/gstreamer-0.10/libgstvideo4linux.so %{_libdir}/gstreamer-0.10/libgstaudioresample.so %{_libdir}/gstreamer-0.10/libgstapp.so %{_libdir}/gstreamer-0.10/libgstxvimagesink.so @@ -134,7 +153,6 @@ rm -rf %{buildroot}/tmp/dump %{_libdir}/gstreamer-0.10/libgsttheora.so %{_libdir}/gstreamer-0.10/libgstvorbis.so %{_libdir}/gstreamer-0.10/libgstximagesink.so -%{_libdir}/gstreamer-0.10/libgstpango.so %{_libdir}/gstreamer-0.10/libgstgio.so # data %{_datadir}/gst-plugins-base/license-translations.dict @@ -250,6 +268,7 @@ rm -rf %{buildroot}/tmp/dump %{_libdir}/pkgconfig/*.pc %files tools +%manifest gst-plugins-base-tools.manifest %defattr(-,root,root,-) # helper programs %{_bindir}/gst-discoverer-0.10 diff --git a/sys/xvimage/Makefile.am b/sys/xvimage/Makefile.am index fbff4d8..1cff228 100644 --- a/sys/xvimage/Makefile.am +++ b/sys/xvimage/Makefile.am @@ -1,13 +1,18 @@ plugin_LTLIBRARIES = libgstxvimagesink.la libgstxvimagesink_la_SOURCES = xvimagesink.c -libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) +libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) $(XFIXES_CFLAGS) $(DRI2PROTO_CFLAGS) $(DRI2_CFLAGS) $(TBM_CFLAGS) $(UTILX_CFLAGS) $(VCONF_CFLAGS) $(DRM_CFLAGS) $(DRM_DEVEL_CFLAGS) +#libgstxvimagesink_la_CFLAGS = $(SAVSCODEC_HEVC_CFLAGS) libgstxvimagesink_la_LIBADD = \ $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \ $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la \ $(GST_BASE_LIBS) \ $(GST_LIBS) \ - $(X_LIBS) $(XVIDEO_LIBS) $(XSHM_LIBS) $(LIBM) + $(XFIXES_LIBS) \ + $(DRI2PROTO_LIBS) \ + $(DRI2_LIBS) \ + $(TBM_LIBS) \ + $(X_LIBS) $(XVIDEO_LIBS) $(XSHM_LIBS) $(LIBM) $(UTILX_LIBS) $(VCONF_LIBS) $(DRM_LIBS) $(DRM_DEVEL_LIBS) libgstxvimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstxvimagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/sys/xvimage/xv_types.h b/sys/xvimage/xv_types.h old mode 100644 new mode 100755 index bbcc07d..5afaf48 --- a/sys/xvimage/xv_types.h +++ b/sys/xvimage/xv_types.h @@ -1,12 +1,45 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Boram Park + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + /* */ /* File name : xv_types.h */ -/* Author : YoungHoon Jung (yhoon.jung@samsung.com) */ +/* Author : Boram Park (boram1288.park@samsung.com) */ /* Protocol Version : 1.0.1 (Dec 16th 2009) */ /* This file is for describing Xv APIs' buffer encoding method. */ /* */ -#define XV_PUTIMAGE_HEADER 0xDEADCD01 -#define XV_PUTIMAGE_VERSION 0x00010001 +#ifndef __XV_TYPE_H__ +#define __XV_TYPE_H__ + +#define XV_DATA_HEADER 0xDEADCD01 +#define XV_DATA_VERSION 0x00010001 /* Return Values */ #define XV_OK 0 @@ -14,24 +47,56 @@ #define XV_VERSION_MISMATCH -2 /* Video Mode */ -#define DISPLAY_MODE_DEFAULT 0 +#define DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE 0 #define DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN 1 #define DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN 2 +/* Color space range */ +#define CSC_RANGE_NARROW 0 +#define CSC_RANGE_WIDE 1 + +/* Buffer Type */ +#define XV_BUF_TYPE_DMABUF 0 +#define XV_BUF_TYPE_LEGACY 1 +#define XV_BUF_PLANE_NUM 3 + /* Data structure for XvPutImage / XvShmPutImage */ -typedef struct { - unsigned int _header; /* for internal use only */ - unsigned int _version; /* for internal use only */ - - unsigned int YPhyAddr; - unsigned int CbPhyAddr; - unsigned int CrPhyAddr; - unsigned int RotAngle; - unsigned int VideoMode; -} XV_PUTIMAGE_DATA, * XV_PUTIMAGE_DATA_PTR; - -static void XV_PUTIMAGE_INIT_DATA(XV_PUTIMAGE_DATA_PTR data) +typedef struct { - data->_header = XV_PUTIMAGE_HEADER; - data->_version = XV_PUTIMAGE_VERSION; + unsigned int _header; /* for internal use only */ + unsigned int _version; /* for internal use only */ + + unsigned int YBuf; + unsigned int CbBuf; + unsigned int CrBuf; + unsigned int BufType; + unsigned int dmabuf_fd[XV_BUF_PLANE_NUM]; + unsigned int gem_handle[XV_BUF_PLANE_NUM]; + void *bo[XV_BUF_PLANE_NUM]; +} XV_DATA, * XV_DATA_PTR; + +static void +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_INIT_DATA (XV_DATA_PTR data) +{ + data->_header = XV_DATA_HEADER; + data->_version = XV_DATA_VERSION; } + +static int +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_VALIDATE_DATA (XV_DATA_PTR data) +{ + if (data->_header != XV_DATA_HEADER) + return XV_HEADER_ERROR; + if (data->_version != XV_DATA_VERSION) + return XV_VERSION_MISMATCH; + return XV_OK; +} + +#endif + diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c old mode 100644 new mode 100755 index 079f82a..5a0d67f --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -1,6 +1,7 @@ /* GStreamer * Copyright (C) <2005> Julien Moutte * <2009>,<2010> Stefan Kost + * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -16,6 +17,11 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * * Modifications by Samsung Electronics Co., Ltd. + * 1. Add display related properties + * 2. Support samsung extension format to improve performance + * 3. Support video texture overlay of OSP layer */ /** @@ -129,6 +135,59 @@ /* For xv extension header for buffer transfer (output) */ #include "xv_types.h" +/* headers for drm */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* for setting vconf about xv state */ +#include +#include + + +enum { + SECURE_PATH_INIT = -1, + SECURE_PATH_OFF = 0, + SECURE_PATH_ON = 1 +}; + +enum { + DRM_LEVEL_0 = 0, + DRM_LEVEL_1 + }; + +enum +{ + DISPLAY_STATUS_NULL = 0, + DISPLAY_STATUS_HDMI_ACTIVE, + DISPLAY_STATUS_UNKNOWN_ACTIVE, +}; + +enum +{ + XV_STATUS_NULL = 0, + XV_STATUS_READY, + XV_STATUS_PAUSED, + XV_STATUS_PLAYING, + XV_STATUS_SEEK, +}; + +typedef enum { + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD, + BUF_SHARE_METHOD_TIZEN_BUFFER, + BUF_SHARE_METHOD_FLUSH_BUFFER +} buf_share_method_t; + +#define _CHECK_DISPLAYED_BUFFER_COUNT 15 +#define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */ + /* max channel count *********************************************************/ #define SCMN_IMGB_MAX_PLANE (4) @@ -157,28 +216,48 @@ typedef struct { /* width of each image plane */ - int w[SCMN_IMGB_MAX_PLANE]; + int w[SCMN_IMGB_MAX_PLANE]; /* height of each image plane */ - int h[SCMN_IMGB_MAX_PLANE]; + int h[SCMN_IMGB_MAX_PLANE]; /* stride of each image plane */ - int s[SCMN_IMGB_MAX_PLANE]; + int s[SCMN_IMGB_MAX_PLANE]; /* elevation of each image plane */ - int e[SCMN_IMGB_MAX_PLANE]; + int e[SCMN_IMGB_MAX_PLANE]; /* user space address of each image plane */ - void * a[SCMN_IMGB_MAX_PLANE]; + void *a[SCMN_IMGB_MAX_PLANE]; /* physical address of each image plane, if needs */ - void * p[SCMN_IMGB_MAX_PLANE]; + void *p[SCMN_IMGB_MAX_PLANE]; /* color space type of image */ - int cs; + int cs; /* left postion, if needs */ - int x; + int x; /* top position, if needs */ - int y; + int y; /* to align memory */ - int __dummy2; + int __dummy2; /* arbitrary data */ - int data[16]; + int data[16]; + /* dma buf fd */ + int dmabuf_fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; + /* Y plane size in case of ST12 */ + int y_size; + /* UV plane size in case of ST12 */ + int uv_size; + /* Tizen buffer object */ + void *bo[SCMN_IMGB_MAX_PLANE]; + /* JPEG data */ + void *jpeg_data; + /* JPEG size */ + int jpeg_size; + /* TZ memory buffer */ + int tz_enable; } SCMN_IMGB; + +static void _release_flush_buffer(GstXvImageSink *xvimagesink); +static void _remove_last_buffer(GstXvImageSink *xvimagesink); +static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink); #endif /* GST_EXT_XV_ENHANCEMENT */ /* Debugging category */ @@ -192,6 +271,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); #ifdef GST_EXT_XV_ENHANCEMENT #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type()) +#define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type()) static GType gst_xvimagesink_display_mode_get_type(void) @@ -211,6 +291,23 @@ gst_xvimagesink_display_mode_get_type(void) return xvimagesink_display_mode_type; } +static GType +gst_xvimagesink_csc_range_get_type(void) +{ + static GType xvimagesink_csc_range_type = 0; + static const GEnumValue csc_range_type[] = { + { 0, "Narrow range", "NARROW"}, + { 1, "Wide range", "WIDE"}, + { 2, NULL, NULL}, + }; + + if (!xvimagesink_csc_range_type) { + xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type); + } + + return xvimagesink_csc_range_type; +} + enum { DEGREE_0, DEGREE_90, @@ -245,13 +342,32 @@ enum { DISP_GEO_METHOD_ORIGIN_SIZE, DISP_GEO_METHOD_FULL_SCREEN, DISP_GEO_METHOD_CROPPED_FULL_SCREEN, - DISP_GEO_METHOD_CUSTOM_ROI, + DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX, + DISP_GEO_METHOD_CUSTOM_DST_ROI, DISP_GEO_METHOD_NUM, }; -#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX +enum { + ROI_DISP_GEO_METHOD_FULL_SCREEN = 0, + ROI_DISP_GEO_METHOD_LETTER_BOX, + ROI_DISP_GEO_METHOD_NUM, +}; + +#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX +#define DEF_ROI_DISPLAY_GEOMETRY_METHOD ROI_DISP_GEO_METHOD_FULL_SCREEN + +enum { + FLIP_NONE = 0, + FLIP_HORIZONTAL, + FLIP_VERTICAL, + FLIP_BOTH, + FLIP_NUM, +}; +#define DEF_DISPLAY_FLIP FLIP_NONE #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type()) +#define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type()) +#define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type()) static GType gst_xvimagesink_display_geometry_method_get_type(void) @@ -262,8 +378,9 @@ gst_xvimagesink_display_geometry_method_get_type(void) { 1, "Origin size", "ORIGIN_SIZE"}, { 2, "Full-screen", "FULL_SCREEN"}, { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"}, - { 4, "Explicitely described destination ROI", "CUSTOM_ROI"}, - { 5, NULL, NULL}, + { 4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"}, + { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"}, + { 6, NULL, NULL}, }; if (!xvimagesink_display_geometry_method_type) { @@ -272,6 +389,92 @@ gst_xvimagesink_display_geometry_method_get_type(void) return xvimagesink_display_geometry_method_type; } + +static GType +gst_xvimagesink_roi_display_geometry_method_get_type(void) +{ + static GType xvimagesink_roi_display_geometry_method_type = 0; + static const GEnumValue roi_display_geometry_method_type[] = { + { 0, "ROI-Full-screen", "FULL_SCREEN"}, + { 1, "ROI-Letter box", "LETTER_BOX"}, + { 2, NULL, NULL}, + }; + + if (!xvimagesink_roi_display_geometry_method_type) { + xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type); + } + + return xvimagesink_roi_display_geometry_method_type; +} + +static GType +gst_xvimagesink_flip_get_type(void) +{ + static GType xvimagesink_flip_type = 0; + static const GEnumValue flip_type[] = { + { FLIP_NONE, "Flip NONE", "FLIP_NONE"}, + { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"}, + { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"}, + { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"}, + { FLIP_NUM, NULL, NULL}, + }; + + if (!xvimagesink_flip_type) { + xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type); + } + + return xvimagesink_flip_type; +} + +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +void +gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1, + gpointer arg_1, + gpointer data2); + register GMarshalFunc_BOOLEAN__POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } else { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_pointer (param_values + 1), + data2); + + g_value_set_boolean (return_value, v_return); +} + +enum +{ + SIGNAL_FRAME_RENDER_ERROR, + SIGNAL_DISPLAY_STATUS, + SIGNAL_EXTERNAL_RESOLUTION, + SIGNAL_WINDOW_STATUS, + SIGNAL_QUICKPANEL_STATUS, + SIGNAL_MULTIWINDOW_STATUS, + LAST_SIGNAL +}; +static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 }; + #endif /* GST_EXT_XV_ENHANCEMENT */ typedef struct @@ -286,6 +489,11 @@ MotifWmHints, MwmHints; #define MWM_HINTS_DECORATIONS (1L << 1) +#ifdef GST_EXT_XV_ENHANCEMENT +#define MAX_DISPLAY_IN_XVIMAGESINK 20 +static Display *g_display_id[MAX_DISPLAY_IN_XVIMAGESINK] = {0}; +#endif + static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink); static GstBufferClass *xvimage_buffer_parent_class = NULL; @@ -300,6 +508,16 @@ static void gst_xvimagesink_expose (GstXOverlay * overlay); #ifdef GST_EXT_XV_ENHANCEMENT static XImage *make_transparent_image(Display *d, Window win, int w, int h); static gboolean set_display_mode(GstXContext *xcontext, int set_mode); +static gboolean set_csc_range(GstXContext *xcontext, int set_range); +static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id); +static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle); +static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle); +static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer); +static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name); +static int _is_connected_to_external_display(GstXvImageSink *xvimagesink); +static void check_hdmi_connected(GstXvImageSink *xvimagesink); +static int get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type, unsigned int *val, unsigned int len); +static gboolean check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name); #endif /* GST_EXT_XV_ENHANCEMENT */ /* Default template - initiated with class struct to allow gst-register to work @@ -340,15 +558,37 @@ enum PROP_WINDOW_HEIGHT, #ifdef GST_EXT_XV_ENHANCEMENT PROP_DISPLAY_MODE, + PROP_CSC_RANGE, PROP_ROTATE_ANGLE, + PROP_FLIP, PROP_DISPLAY_GEOMETRY_METHOD, PROP_VISIBLE, PROP_ZOOM, + PROP_ZOOM_POS_X, + PROP_ZOOM_POS_Y, + PROP_ORIENTATION, + PROP_DST_ROI_MODE, PROP_DST_ROI_X, PROP_DST_ROI_Y, PROP_DST_ROI_W, PROP_DST_ROI_H, + PROP_SRC_CROP_X, + PROP_SRC_CROP_Y, + PROP_SRC_CROP_W, + PROP_SRC_CROP_H, PROP_STOP_VIDEO, + PROP_PIXMAP_CB, + PROP_PIXMAP_CB_USER_DATA, + PROP_SUBPICTURE, + PROP_EXTERNAL_WIDTH, + PROP_EXTERNAL_HEIGHT, + PROP_ENABLE_FLUSH_BUFFER, + PROP_PIXMAP, + PROP_HIDED_WINDOW, + PROP_QUICKPANEL_ON, + PROP_MULTIWINDOW_ACTIVE, + PROP_KEEP_EXTERNAL_FULLSCREEN_POST, + PROP_KEEP_EXTERNAL_FULLSCREEN_PREV, #endif /* GST_EXT_XV_ENHANCEMENT */ }; @@ -560,8 +800,23 @@ gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent) char error_msg[1024]; XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; +#ifndef GST_EXT_XV_ENHANCEMENT + GST_DEBUG ("xvimagesink triggered an XError. error: %s, display(%p)", error_msg, display); +#else + { + int i = 0; + for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) { + if (g_display_id[i] == display) { + GST_ERROR ("xvimagesink triggered an XError. error: %s, display(%p), xevent->request_code: %d", error_msg, display, xevent->request_code); + error_caught = TRUE; + break; + } + } + if (i == MAX_DISPLAY_IN_XVIMAGESINK) { + GST_ERROR ("xvimagesink triggered an XError. error: %s, xevent->request_code: %d, but the display(%p) was not created in xvimagesink, skip it...", error_msg, xevent->request_code, display); + } + } +#endif return 0; } @@ -703,6 +958,10 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) xvimagesink->aligned_width = xvimage->width; xvimagesink->aligned_height = xvimage->height; } + if (xvimagesink->subpicture) { + GST_LOG("because of subpicture's format, pass xvimage_new"); + return xvimage; + } #endif /* GST_EXT_XV_ENHANCEMENT */ xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); @@ -718,6 +977,9 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) g_mutex_lock (xvimagesink->x_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + XSync (xvimagesink->xcontext->disp, FALSE); +#endif /* GST_EXT_XV_ENHANCEMENT */ /* Setting an error handler to catch failure */ error_caught = FALSE; handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); @@ -747,12 +1009,18 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) ("could not XvShmCreateImage a %dx%d image", xvimage->width, xvimage->height)); +#ifdef GST_EXT_XV_ENHANCEMENT + /* must not change "use_xshm", + because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */ + goto beach_unlocked; +#else /* GST_EXT_XV_ENHANCEMENT */ /* Retry without XShm */ xvimagesink->xcontext->use_xshm = FALSE; /* Hold X mutex again to try without XShm */ g_mutex_lock (xvimagesink->x_lock); goto no_xshm; +#endif /* GST_EXT_XV_ENHANCEMENT */ } /* we have to use the returned data_size for our shm size */ @@ -796,6 +1064,7 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) #ifdef GST_EXT_XV_ENHANCEMENT case GST_MAKE_FOURCC ('S', 'T', '1', '2'): case GST_MAKE_FOURCC ('S', 'N', '1', '2'): + case GST_MAKE_FOURCC ('S', 'N', '2', '1'): case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'): case GST_MAKE_FOURCC ('S', '4', '2', '0'): @@ -872,7 +1141,9 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx", xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg); } else +#ifndef GST_EXT_XV_ENHANCEMENT no_xshm: +#endif /* GST_EXT_XV_ENHANCEMENT */ #endif /* HAVE_XSHM */ { xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp, @@ -978,33 +1249,74 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, #ifdef GST_EXT_XV_ENHANCEMENT static Atom atom_rotation = None; + static Atom atom_hflip = None; + static Atom atom_vflip = None; + static Atom atom_contents_rotation = None; + gboolean set_hflip = FALSE; + gboolean set_vflip = FALSE; + XWindowAttributes map_attr; GstVideoRectangle src_origin = { 0, 0, 0, 0}; GstVideoRectangle src_input = { 0, 0, 0, 0}; GstVideoRectangle src = { 0, 0, 0, 0}; GstVideoRectangle dst = { 0, 0, 0, 0}; + gint res_rotate_angle = 0; int rotate = 0; + int orientation = 0; int ret = 0; + int idx = 0; + int (*handler) (Display *, XErrorEvent *) = NULL; + gboolean res = FALSE; + XV_DATA_PTR img_data = NULL; + + if (xvimagesink->is_subpicture_format) + return TRUE; #endif /* GST_EXT_XV_ENHANCEMENT */ /* We take the flow_lock. If expose is in there we don't want to run concurrently from the data flow thread */ g_mutex_lock (xvimagesink->flow_lock); - if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { #ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." ); + if (xvimagesink->xid_updated) { + if (xvimage && xvimagesink->xvimage == NULL) { + GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage"); + xvimage = NULL; + } + xvimagesink->xid_updated = FALSE; + } #endif /* GST_EXT_XV_ENHANCEMENT */ + + if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { +#ifdef GST_EXT_XV_ENHANCEMENT + if (xvimagesink->get_pixmap_cb) { + GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb ); + } else { + GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." ); + g_mutex_unlock(xvimagesink->flow_lock); + return FALSE; + } +#else /* GST_EXT_XV_ENHANCEMENT */ g_mutex_unlock (xvimagesink->flow_lock); return FALSE; +#endif /* GST_EXT_XV_ENHANCEMENT */ } #ifdef GST_EXT_XV_ENHANCEMENT - if (xvimagesink->visible == FALSE) { - GST_INFO_OBJECT(xvimagesink, "visible is FALSE. Skip xvimage_put."); - g_mutex_unlock(xvimagesink->flow_lock); - return TRUE; + /* check map status of window */ + if(!xvimagesink->is_pixmap) { + if (xvimagesink->xcontext && xvimagesink->xwindow) { + if (XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &map_attr)) { + if (map_attr.map_state != IsViewable) { + GST_WARNING_OBJECT(xvimagesink, "window is unmapped, skip putimage"); + g_mutex_unlock(xvimagesink->flow_lock); + return TRUE; + } + } else { + GST_WARNING_OBJECT(xvimagesink, "XGetWindowAttributes failed"); + } + } } #endif /* GST_EXT_XV_ENHANCEMENT */ @@ -1027,12 +1339,24 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, /* Expose sends a NULL image, we take the latest frame */ if (!xvimage) { +#ifdef GST_EXT_XV_ENHANCEMENT + g_mutex_lock(xvimagesink->display_buffer_lock); + if (xvimagesink->is_zero_copy_format && + xvimagesink->displaying_buffer_count < 1) { + g_mutex_unlock(xvimagesink->display_buffer_lock); + g_mutex_unlock (xvimagesink->flow_lock); + GST_WARNING_OBJECT(xvimagesink, "no buffer to display. skip putimage"); + return TRUE; + } + g_mutex_unlock(xvimagesink->display_buffer_lock); +#endif /* GST_EXT_XV_ENHANCEMENT */ if (xvimagesink->cur_image) { draw_border = TRUE; xvimage = xvimagesink->cur_image; } else { #ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put."); + GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put."); + /* no need to release gem handle */ #endif /* GST_EXT_XV_ENHANCEMENT */ g_mutex_unlock (xvimagesink->flow_lock); return TRUE; @@ -1040,7 +1364,59 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, } #ifdef GST_EXT_XV_ENHANCEMENT - gst_xvimagesink_xwindow_update_geometry( xvimagesink ); + gboolean enable_last_buffer; + g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL); + if(enable_last_buffer) { + if (xvimagesink->cur_image && xvimagesink->is_zero_copy_format) { + GstBuffer *last_buffer= NULL; + g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL); + if (last_buffer) { + if(last_buffer != xvimagesink->cur_image) + { + GST_LOG("curimage : %p , last_buffer : %p", xvimagesink->cur_image, last_buffer); + } + } else { + GST_WARNING_OBJECT(xvimagesink, "zero copy format and last buffer is NULL, so skip this putimage"); + g_mutex_unlock (xvimagesink->flow_lock); + return TRUE; + } + gst_buffer_unref(last_buffer); + last_buffer = NULL; + } + } + + if (xvimagesink->visible == FALSE || + (xvimagesink->is_hided && GST_STATE(xvimagesink) != GST_STATE_PLAYING)) { + GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.", + xvimagesink->visible, xvimagesink->is_hided); + g_mutex_unlock(xvimagesink->flow_lock); + return TRUE; + } + + if (!xvimagesink->get_pixmap_cb) { + gst_xvimagesink_xwindow_update_geometry( xvimagesink ); + if (!xvimagesink->subpicture && !xvimagesink->is_during_seek) { + if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) { + set_display_mode(xvimagesink->xcontext, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE); + } else { + set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode); + } + } + } else { + /* for multi-pixmap usage for the video texture */ + gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data)); + idx = xvimagesink->current_pixmap_idx; + if (idx == -1) { + g_mutex_unlock (xvimagesink->flow_lock); + return FALSE; + } else if (idx == -2) { + GST_WARNING_OBJECT(xvimagesink, "Skip putImage()"); + g_mutex_unlock (xvimagesink->flow_lock); + return TRUE; + } + } + + res_rotate_angle = xvimagesink->rotate_angle; src.x = src.y = 0; src_origin.x = src_origin.y = src_input.x = src_input.y = 0; @@ -1048,6 +1424,19 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, src_input.w = src_origin.w = xvimagesink->video_width; src_input.h = src_origin.h = xvimagesink->video_height; + if ((xvimagesink->display_geometry_method == DISP_GEO_METHOD_LETTER_BOX || + xvimagesink->display_geometry_method == DISP_GEO_METHOD_FULL_SCREEN || + xvimagesink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_DST_ROI) && + xvimagesink->src_crop.w && xvimagesink->src_crop.h) { + GST_LOG_OBJECT(xvimagesink, "set src crop %d,%d,%dx%d -> %d,%d,%dx%d", + src_input.x, src_input.y, src_input.w, src_input.h, + xvimagesink->src_crop.x, xvimagesink->src_crop.y, xvimagesink->src_crop.w, xvimagesink->src_crop.h); + src_input.x = src_origin.w = xvimagesink->src_crop.x; + src_input.y = src_origin.y = xvimagesink->src_crop.y; + src_input.w = src_origin.w = xvimagesink->src_crop.w; + src_input.h = src_origin.h = xvimagesink->src_crop.h; + } + if (xvimagesink->rotate_angle == DEGREE_0 || xvimagesink->rotate_angle == DEGREE_180) { src.w = src_origin.w; @@ -1086,8 +1475,13 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, case DISP_GEO_METHOD_FULL_SCREEN: result.x = result.y = 0; - result.w = xvimagesink->xwindow->width; - result.h = xvimagesink->xwindow->height; + if (!xvimagesink->get_pixmap_cb) { + result.w = xvimagesink->xwindow->width; + result.h = xvimagesink->xwindow->height; + } else { + result.w = xvimagesink->xpixmap[idx]->width; + result.h = xvimagesink->xpixmap[idx]->height; + } break; case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: @@ -1109,66 +1503,185 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, } break; - case DISP_GEO_METHOD_CUSTOM_ROI: -#ifdef GST_EXT_XV_ENHANCEMENT_ROI_MODE + case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: + if (src.w > dst.w || src.h > dst.h) { + /* LETTER BOX */ + gst_video_sink_center_rect (src, dst, &result, TRUE); + result.x += xvimagesink->render_rect.x; + result.y += xvimagesink->render_rect.y; + } else { + /* ORIGIN SIZE */ + gst_video_sink_center_rect (src, dst, &result, FALSE); + gst_video_sink_center_rect (dst, src, &src_input, FALSE); + + if (xvimagesink->rotate_angle == DEGREE_90 || + xvimagesink->rotate_angle == DEGREE_270) { + src_input.x = src_input.x ^ src_input.y; + src_input.y = src_input.x ^ src_input.y; + src_input.x = src_input.x ^ src_input.y; + + src_input.w = src_input.w ^ src_input.h; + src_input.h = src_input.w ^ src_input.h; + src_input.w = src_input.w ^ src_input.h; + } + } + break; + + case DISP_GEO_METHOD_CUSTOM_DST_ROI: + { + GstVideoRectangle dst_roi_cmpns; + dst_roi_cmpns.w = xvimagesink->dst_roi.w; + dst_roi_cmpns.h = xvimagesink->dst_roi.h; + dst_roi_cmpns.x = xvimagesink->dst_roi.x; + dst_roi_cmpns.y = xvimagesink->dst_roi.y; + + /* setting for DST ROI mode */ + switch (xvimagesink->dst_roi_mode) { + case ROI_DISP_GEO_METHOD_FULL_SCREEN: + break; + case ROI_DISP_GEO_METHOD_LETTER_BOX: + { + GstVideoRectangle roi_result; + if (xvimagesink->orientation == DEGREE_0 || + xvimagesink->orientation == DEGREE_180) { + src.w = src_origin.w; + src.h = src_origin.h; + } else { + src.w = src_origin.h; + src.h = src_origin.w; + } + dst.w = xvimagesink->dst_roi.w; + dst.h = xvimagesink->dst_roi.h; + + gst_video_sink_center_rect (src, dst, &roi_result, TRUE); + dst_roi_cmpns.w = roi_result.w; + dst_roi_cmpns.h = roi_result.h; + dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x; + dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y; + } + break; + default: + break; + } + + /* calculating coordinates according to rotation angle for DST ROI */ switch (xvimagesink->rotate_angle) { case DEGREE_90: - result.w = xvimagesink->dst_roi.h; - result.h = xvimagesink->dst_roi.w; + result.w = dst_roi_cmpns.h; + result.h = dst_roi_cmpns.w; - result.x = xvimagesink->dst_roi.y; - result.y = xvimagesink->xwindow->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w; + result.x = dst_roi_cmpns.y; + if (!xvimagesink->get_pixmap_cb) { + result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w; + } else { + result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w; + } break; case DEGREE_180: - result.w = xvimagesink->dst_roi.w; - result.h = xvimagesink->dst_roi.h; + result.w = dst_roi_cmpns.w; + result.h = dst_roi_cmpns.h; - result.x = xvimagesink->xwindow->width - result.w - xvimagesink->dst_roi.x; - result.y = xvimagesink->xwindow->height - result.h - xvimagesink->dst_roi.y; + if (!xvimagesink->get_pixmap_cb) { + result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x; + result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y; + } else { + result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x; + result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y; + } break; case DEGREE_270: - result.w = xvimagesink->dst_roi.h; - result.h = xvimagesink->dst_roi.w; + result.w = dst_roi_cmpns.h; + result.h = dst_roi_cmpns.w; - result.x = xvimagesink->xwindow->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h; - result.y = xvimagesink->dst_roi.x; + if (!xvimagesink->get_pixmap_cb) { + result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h; + } else { + result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h; + } + result.y = dst_roi_cmpns.x; break; default: - result.x = xvimagesink->dst_roi.x; - result.y = xvimagesink->dst_roi.y; - result.w = xvimagesink->dst_roi.w; - result.h = xvimagesink->dst_roi.h; + result.x = dst_roi_cmpns.x; + result.y = dst_roi_cmpns.y; + result.w = dst_roi_cmpns.w; + result.h = dst_roi_cmpns.h; break; } - GST_LOG_OBJECT(xvimagesink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]", - xvimagesink->rotate_angle, + /* orientation setting for auto rotation in DST ROI */ + if (xvimagesink->orientation) { + res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation); + if (res_rotate_angle < 0) { + res_rotate_angle += DEGREE_NUM; + } + GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]", + xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle); + } + + GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]", + xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode, xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h, result.x, result.y, result.w, result.h); -#else /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */ - result.x = xvimagesink->dst_roi.x; - result.y = xvimagesink->dst_roi.y; - result.w = xvimagesink->dst_roi.w; - result.h = xvimagesink->dst_roi.h; - - if (xvimagesink->rotate_angle == DEGREE_90 || - xvimagesink->rotate_angle == DEGREE_270) { - result.w = xvimagesink->dst_roi.h; - result.h = xvimagesink->dst_roi.w; - } -#endif /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */ break; - + } default: break; } - if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) { - src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1; - src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1; - src_input.w /= xvimagesink->zoom; - src_input.h /= xvimagesink->zoom; + if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) { + GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]", + xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h); + gint default_offset_x = 0; + gint default_offset_y = 0; + gfloat w = (gfloat)src_input.w; + gfloat h = (gfloat)src_input.h; + if (xvimagesink->orientation == DEGREE_0 || + xvimagesink->orientation == DEGREE_180) { + default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1; + default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1; + } else { + default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1; + default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1; + } + GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation); + if (xvimagesink->zoom_pos_x == -1) { + src_input.x += default_offset_x; + } else { + if (xvimagesink->orientation == DEGREE_0 || + xvimagesink->orientation == DEGREE_180) { + if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) { + xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom); + } + src_input.x += xvimagesink->zoom_pos_x; + } else { + if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) { + xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom); + } + src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x; + } + } + if (xvimagesink->zoom_pos_y == -1) { + src_input.y += default_offset_y; + } else { + if (xvimagesink->orientation == DEGREE_0 || + xvimagesink->orientation == DEGREE_180) { + if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) { + xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom); + } + src_input.y += xvimagesink->zoom_pos_y; + } else { + if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) { + xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom); + } + src_input.x += (xvimagesink->zoom_pos_y); + } + } + src_input.w = (gint)(w/xvimagesink->zoom); + src_input.h = (gint)(h/xvimagesink->zoom); + GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]", + xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y); } + #else /* GST_EXT_XV_ENHANCEMENT */ if (xvimagesink->keep_aspect) { GstVideoRectangle src, dst; @@ -1190,7 +1703,11 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, g_mutex_lock (xvimagesink->x_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) { +#else if (draw_border && xvimagesink->draw_borders) { +#endif /* GST_EXT_XV_ENHANCEMENT */ gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow, result); xvimagesink->redraw_border = FALSE; @@ -1206,7 +1723,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage); #ifdef GST_EXT_XV_ENHANCEMENT - switch( xvimagesink->rotate_angle ) + switch( res_rotate_angle ) { /* There's slightly weired code (CCW? CW?) */ case DEGREE_0: @@ -1222,7 +1739,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, break; default: GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.", - xvimagesink->rotate_angle ); + res_rotate_angle ); break; } @@ -1234,31 +1751,168 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, src_input.h += 1; } - GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]", - xvimagesink->scr_w, xvimagesink->scr_h, - xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height, + if (!xvimagesink->get_pixmap_cb) { + GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]", + xvimagesink->scr_w, xvimagesink->scr_h, + xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height, + xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode, + src_origin.w, src_origin.h, + dst.x, dst.y, dst.w, dst.h, + src_input.x, src_input.y, src_input.w, src_input.h, + result.x, result.y, result.w, result.h ); + } else { + GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]", + xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height, xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode, src_origin.w, src_origin.h, dst.x, dst.y, dst.w, dst.h, src_input.x, src_input.y, src_input.w, src_input.h, result.x, result.y, result.w, result.h ); + } + /* skip request to render if dst rect is 0 */ + if (xvimagesink->is_zero_copy_format && (!result.w || !result.h)) { + GST_WARNING_OBJECT(xvimagesink, "result.w[%d] or result.h[%d] is 0. Skip xvimage_put.", result.w, result.h); + g_mutex_unlock(xvimagesink->x_lock); + g_mutex_unlock(xvimagesink->flow_lock); + return TRUE; + } + + static gboolean is_exist = FALSE; + gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_ROTATION"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); - if (atom_rotation == None) { - atom_rotation = XInternAtom(xvimagesink->xcontext->disp, + if (is_exist) { + /* set display rotation */ + if (atom_rotation == None) { + atom_rotation = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_ROTATION", False); + } + ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, + atom_rotation, rotate); + if (ret != Success) { + GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]", + ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate ); + + g_mutex_unlock(xvimagesink->x_lock); + g_mutex_unlock(xvimagesink->flow_lock); + return FALSE; + } + } else { + GST_WARNING("_USER_WM_PORT_ATTRIBUTE_ROTATION is not existed"); } - ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate); - if (ret != Success) { - GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]", - ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate ); - return FALSE; + switch( xvimagesink->orientation ) + { + case DEGREE_0: + orientation = 0; + break; + case DEGREE_90: + orientation = 90; + break; + case DEGREE_180: + orientation = 180; + break; + case DEGREE_270: + orientation = 270; + break; + default: + GST_WARNING_OBJECT( xvimagesink, "Unsupported orientation [%d]...", + xvimagesink->orientation ); + break; + } + + is_exist = FALSE; + attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + + if (is_exist) { + /* set contents rotation for connecting with external display */ + if (atom_contents_rotation == None) { + atom_contents_rotation = XInternAtom(xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION", False); + } + ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, + atom_contents_rotation, orientation); + if (ret != Success) { + GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],orientation[%d]", + ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_contents_rotation, orientation ); + + g_mutex_unlock(xvimagesink->x_lock); + g_mutex_unlock(xvimagesink->flow_lock); + return FALSE; + } + }else { + GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION is not existed"); + } + + switch (xvimagesink->flip) { + case FLIP_HORIZONTAL: + set_hflip = TRUE; + set_vflip = FALSE; + break; + case FLIP_VERTICAL: + set_hflip = FALSE; + set_vflip = TRUE; + break; + case FLIP_BOTH: + set_hflip = TRUE; + set_vflip = TRUE; + break; + case FLIP_NONE: + default: + set_hflip = FALSE; + set_vflip = FALSE; + break; + } + + GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip); + + is_exist = FALSE; + attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_HFLIP"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + + if (is_exist) { + if (atom_hflip == None) { + /* set display flip */ + atom_hflip = XInternAtom(xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_HFLIP", False); + } + ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip); + if (ret != Success) { + GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]", + ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip); + } + } + + is_exist = FALSE; + attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_VFLIP"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + + if (is_exist) { + if (atom_vflip == None) { + /* set display flip */ + atom_vflip = XInternAtom(xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_VFLIP", False); + } + ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip); + if (ret != Success) { + GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]", + ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip); + } } + /* set error handler */ + error_caught = FALSE; + handler = XSetErrorHandler(gst_xvimagesink_handle_xerror); + /* src input indicates the status when degree is 0 */ /* dst input indicates the area that src will be shown regardless of rotate */ - - if (xvimagesink->visible && !xvimagesink->is_hided) { + if (xvimagesink->visible && + ((!xvimagesink->is_hided) || (xvimagesink->is_hided && (GST_STATE(xvimagesink) == GST_STATE_PLAYING)))) { if (xvimagesink->xim_transparenter) { GST_LOG_OBJECT( xvimagesink, "Transparent related issue." ); XPutImage(xvimagesink->xcontext->disp, @@ -1269,13 +1923,39 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, result.x, result.y, result.w, result.h); } - ret = XvShmPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, xvimage->xvimage, - src_input.x, src_input.y, src_input.w, src_input.h, - result.x, result.y, result.w, result.h, FALSE); - GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret ); + /* store buffer */ + if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) { + img_data = (XV_DATA_PTR)xvimage->xvimage->data; + if (img_data->BufType == XV_BUF_TYPE_DMABUF) { + _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer); + xvimage->current_buffer = NULL; + } + } + + g_mutex_lock(xvimagesink->display_buffer_lock); + if (xvimagesink->displaying_buffer_count > 3) { + GST_WARNING("too many buffers are not released. [displaying_buffer_count %d]", xvimagesink->displaying_buffer_count); + } + g_mutex_unlock(xvimagesink->display_buffer_lock); + + if (xvimagesink->get_pixmap_cb) { + gint idx = xvimagesink->current_pixmap_idx; + ret = XvShmPutImage (xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + xvimagesink->xpixmap[idx]->pixmap, + xvimagesink->xpixmap[idx]->gc, xvimage->xvimage, + src_input.x, src_input.y, src_input.w, src_input.h, + result.x, result.y, result.w, result.h, FALSE); + GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], pixmap id[%d], idx[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xpixmap[idx]->gc, xvimagesink->xpixmap[idx]->pixmap, idx); + } else { + ret = XvShmPutImage (xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + xvimagesink->xwindow->win, + xvimagesink->xwindow->gc, xvimage->xvimage, + src_input.x, src_input.y, src_input.w, src_input.h, + result.x, result.y, result.w, result.h, FALSE); + GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], xid[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xwindow->gc, xvimagesink->xwindow->win); + } } else { GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." ); } @@ -1302,6 +1982,42 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, XSync (xvimagesink->xcontext->disp, FALSE); +#ifdef HAVE_XSHM +#ifdef GST_EXT_XV_ENHANCEMENT + if (ret || error_caught || xvimagesink->get_pixmap_cb) { + GST_DEBUG("error or pixmap_cb"); + + if (ret || error_caught) { + GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d", + ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count); + + if (xvimagesink->get_pixmap_cb) { + g_signal_emit (G_OBJECT (xvimagesink), + gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR], + 0, + &xvimagesink->xpixmap[idx]->pixmap, + &res); + } + } + + /* release gem handle */ + if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) { + unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, }; + gem_name[0] = img_data->YBuf; + gem_name[1] = img_data->CbBuf; + gem_name[2] = img_data->CrBuf; + _remove_displaying_buffer(xvimagesink, gem_name); + } + } + + /* Reset error handler */ + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } +#endif /* GST_EXT_XV_ENHANCEMENT */ +#endif /* HAVE_XSHM */ + g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->flow_lock); @@ -1390,27 +2106,29 @@ gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink, #ifdef GST_EXT_XV_ENHANCEMENT static XImage *make_transparent_image(Display *d, Window win, int w, int h) { - XImage *xim; + XImage *xim; /* create a normal ximage */ xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0); + GST_INFO("ximage %p", xim); + /* allocate data for it */ if (xim) { xim->data = (char *)malloc(xim->bytes_per_line * xim->height); - } - - memset(xim->data, 0x00, xim->bytes_per_line * xim->height); - if (!xim || !xim->data) { - /* failed to create XImage or allocate data memory */ - if (xim) { - XDestroyImage(xim); + if (xim->data) { + memset(xim->data, 0x00, xim->bytes_per_line * xim->height); + return xim; + } else { + GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height); } - return NULL; + XDestroyImage(xim); } - return xim; + GST_ERROR("failed to create Ximage"); + + return NULL; } @@ -1433,19 +2151,24 @@ static gboolean set_display_mode(GstXContext *xcontext, int set_mode) int count = 0; XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp, xcontext->xv_port_id, &count); - is_exist = FALSE; - current_port_id = xcontext->xv_port_id; - for (i = 0 ; i < count ; i++) { - if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) { - is_exist = TRUE; - GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i); - break; + if (attr) { + current_port_id = xcontext->xv_port_id; + for (i = 0 ; i < count ; i++) { + if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) { + is_exist = TRUE; + GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i); + break; + } } + XFree(attr); + } else { + GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed", + xcontext->disp, xcontext->xv_port_id); } } if (is_exist) { - GST_INFO("set display mode %d", set_mode); + GST_DEBUG("set display mode %d", set_mode); atom_output = XInternAtom(xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False); ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id, @@ -1461,6 +2184,687 @@ static gboolean set_display_mode(GstXContext *xcontext, int set_mode) return FALSE; } + + +static gboolean set_csc_range(GstXContext *xcontext, int set_range) +{ + int ret = 0; + static gboolean is_exist = FALSE; + static XvPortID current_port_id = -1; + Atom atom_csc_range = None; + + if (xcontext == NULL) { + GST_WARNING("xcontext is NULL"); + return FALSE; + } + + /* check once per one xv_port_id */ + if (current_port_id != xcontext->xv_port_id) { + /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */ + int i = 0; + int count = 0; + XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp, + xcontext->xv_port_id, &count); + if (attr) { + current_port_id = xcontext->xv_port_id; + for (i = 0 ; i < count ; i++) { + if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) { + is_exist = TRUE; + GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i); + break; + } + } + XFree(attr); + } else { + GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed", + xcontext->disp, xcontext->xv_port_id); + } + } + + if (is_exist) { + GST_WARNING("set csc range %d", set_range); + atom_csc_range = XInternAtom(xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False); + ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id, + atom_csc_range, set_range); + if (ret == Success) { + return TRUE; + } else { + GST_WARNING("csc range[%d] set failed.", set_range); + } + } else { + GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed"); + } + + return FALSE; +} + + +static void drm_init(GstXvImageSink *xvimagesink) +{ + Display *dpy; + int eventBase = 0; + int errorBase = 0; + int dri2Major = 0; + int dri2Minor = 0; + char *driverName = NULL; + char *deviceName = NULL; + struct drm_auth auth_arg = {0}; + + xvimagesink->drm_fd = -1; + + dpy = XOpenDisplay(0); + if (!dpy) { + GST_ERROR("XOpenDisplay failed errno:%d", errno); + return; + } + + GST_INFO("START"); + + /* DRI2 */ + if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) { + GST_ERROR("DRI2QueryExtension !!"); + goto DRM_INIT_ERROR; + } + + if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) { + GST_ERROR("DRI2QueryVersion !!"); + goto DRM_INIT_ERROR; + } + + if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) { + GST_ERROR("DRI2Connect !!"); + goto DRM_INIT_ERROR; + } + + if (!driverName || !deviceName) { + GST_ERROR("driverName or deviceName is not valid"); + goto DRM_INIT_ERROR; + } + + GST_INFO("Open drm device : %s", deviceName); + + /* get the drm_fd though opening the deviceName */ + xvimagesink->drm_fd = open(deviceName, O_RDWR); + if (xvimagesink->drm_fd < 0) { + GST_ERROR("cannot open drm device (%s)", deviceName); + goto DRM_INIT_ERROR; + } + + /* get magic from drm to authentication */ + if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) { + GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd); + goto DRM_INIT_ERROR; + } + + if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) { + GST_ERROR("cannot get drm authentication from X"); + goto DRM_INIT_ERROR; + } + + XCloseDisplay(dpy); + free(driverName); + free(deviceName); + + xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd); + if (xvimagesink->bufmgr == NULL) { + GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed"); + goto DRM_INIT_ERROR; + } + + GST_INFO("DONE"); + + return; + +DRM_INIT_ERROR: + if (xvimagesink->drm_fd >= 0) { + close(xvimagesink->drm_fd); + xvimagesink->drm_fd = -1; + } + if (dpy) { + XCloseDisplay(dpy); + } + if (driverName) { + free(driverName); + } + if (deviceName) { + free(deviceName); + } + + return; +} + +static void drm_fini(GstXvImageSink *xvimagesink) +{ + GST_WARNING_OBJECT(xvimagesink, "START"); + + if (xvimagesink->drm_fd >= 0) { + int i = 0; + int j = 0; + + /* close remained gem handle */ + g_mutex_lock(xvimagesink->display_buffer_lock); + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) { + GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u", + xvimagesink->displaying_buffers[i].buffer, + xvimagesink->displaying_buffers[i].gem_name[0], + xvimagesink->displaying_buffers[i].gem_name[1], + xvimagesink->displaying_buffers[i].gem_name[2], + xvimagesink->displaying_buffers[i].gem_handle[0], + xvimagesink->displaying_buffers[i].gem_handle[1], + xvimagesink->displaying_buffers[i].gem_handle[2]); + + /* release flush buffer */ + if (xvimagesink->flush_buffer) { + if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] && + xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] && + xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) { + _release_flush_buffer(xvimagesink); + } + } else { + GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer"); + } + + for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) { + if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) { + drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j])); + } + xvimagesink->displaying_buffers[i].gem_name[j] = 0; + xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0; + xvimagesink->displaying_buffers[i].bo[j] = NULL; + } + + if (xvimagesink->displaying_buffers[i].buffer) { + gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer); + xvimagesink->displaying_buffers[i].buffer = NULL; + } + } + } + g_mutex_unlock(xvimagesink->display_buffer_lock); + + GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager"); + tbm_bufmgr_deinit(xvimagesink->bufmgr); + xvimagesink->bufmgr = NULL; + + GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd); + close(xvimagesink->drm_fd); + xvimagesink->drm_fd = -1; + } else { + GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened"); + } + + GST_WARNING_OBJECT(xvimagesink, "DONE"); +} + +static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle) +{ + int ret = 0; + + struct drm_prime_handle prime_arg = {0,}; + struct drm_gem_flink flink_arg = {0,}; + + if (!xvimagesink || !gem_handle) { + GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle); + return 0; + } + + if (xvimagesink->drm_fd < 0) { + GST_ERROR("DRM is not opened"); + return 0; + } + + if (dmabuf_fd <= 0) { + GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd); + return 0; + } + + prime_arg.fd = dmabuf_fd; + ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg); + if (ret) { + GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]", + ret, dmabuf_fd, xvimagesink->drm_fd); + return 0; + } + + *gem_handle = prime_arg.handle; + flink_arg.handle = prime_arg.handle; + ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg); + if (ret) { + GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]", + ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd); + return 0; + } + + return flink_arg.name; +} + +static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle) +{ + struct drm_gem_close close_arg = {0,}; + + if (xvimagesink->drm_fd < 0 || !gem_handle) { + GST_ERROR("DRM is not opened"); + return; + } + + if (*gem_handle <= 0) { + GST_DEBUG("invalid gem handle %u", *gem_handle); + return; + } + + GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle); + + close_arg.handle = *gem_handle; + if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) { + GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd); + return; + } + + *gem_handle = 0; + + return; +} + + +static void _remove_last_buffer(GstXvImageSink *xvimagesink) +{ + gboolean enable_last_buffer = FALSE; + + if (xvimagesink == NULL) { + GST_ERROR("handle is NULL"); + return; + } + + /* get enable-last-buffer */ + g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL); + + GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer); + + /* flush if enable-last-buffer is TRUE */ + if (enable_last_buffer) { + g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL); + g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL); + } + + return; +} + + +static void _release_flush_buffer(GstXvImageSink *xvimagesink) +{ + int i = 0; + + if (xvimagesink == NULL || + xvimagesink->flush_buffer == NULL) { + GST_WARNING("handle is NULL"); + return; + } + + GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER"); + + for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) { + if (xvimagesink->flush_buffer->bo[i]) { + tbm_bo_unref(xvimagesink->flush_buffer->bo[i]); + xvimagesink->flush_buffer->bo[i] = NULL; + } + } + + GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done"); + + free(xvimagesink->flush_buffer); + xvimagesink->flush_buffer = NULL; + + return; +} + + +static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer) +{ + int i = 0; + int j = 0; + + if (!xvimagesink || !img_data) { + GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data); + return; + } + + /* lock display buffer mutex */ + g_mutex_lock(xvimagesink->display_buffer_lock); + + /* increase displaying buffer count */ + xvimagesink->displaying_buffer_count++; + + /* check duplicated */ + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) { + if ((img_data->dmabuf_fd[0] > 0 && + xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] && + xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] && + xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) || + (img_data->bo[0] && + xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] && + xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] && + xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) { + /* increase ref count */ + xvimagesink->displaying_buffers[i].ref_count++; + + /* set buffer info */ + img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0]; + img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1]; + img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2]; + + if (img_data->dmabuf_fd[0] > 0) { + GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]", + img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2], + img_data->YBuf, img_data->CbBuf, img_data->CrBuf); + } else { + GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]", + img_data->bo[0], img_data->bo[1], img_data->bo[2], + img_data->YBuf, img_data->CbBuf, img_data->CrBuf); + } + + /* unlock display buffer mutex */ + g_mutex_unlock(xvimagesink->display_buffer_lock); + return; + } + } + } + + /* store buffer temporarily */ + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) { + if (buffer) { + /* increase ref count of buffer */ + gst_buffer_ref(buffer); + xvimagesink->displaying_buffers[i].buffer = buffer; + } + + if (img_data->dmabuf_fd[0] > 0) { + /* convert fd to name */ + img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]); + img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]); + img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]); + } else { + /* export bo */ + if (img_data->bo[0]) { + img_data->YBuf = tbm_bo_export(img_data->bo[0]); + } + if (img_data->bo[1]) { + img_data->CbBuf = tbm_bo_export(img_data->bo[1]); + } + if (img_data->bo[2]) { + img_data->CrBuf = tbm_bo_export(img_data->bo[2]); + } + } + + for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) { + xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j]; + xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j]; + xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j]; + } + + /* set buffer info */ + xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf; + xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf; + xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf; + + /* set ref count */ + xvimagesink->displaying_buffers[i].ref_count = 1; + + if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) { + GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]", + xvimagesink->displayed_buffer_count, + i, xvimagesink->displaying_buffers[i].buffer, + xvimagesink->displaying_buffers[i].dmabuf_fd[0], + xvimagesink->displaying_buffers[i].dmabuf_fd[1], + xvimagesink->displaying_buffers[i].dmabuf_fd[2], + xvimagesink->displaying_buffers[i].gem_handle[0], + xvimagesink->displaying_buffers[i].gem_handle[1], + xvimagesink->displaying_buffers[i].gem_handle[2], + xvimagesink->displaying_buffers[i].gem_name[0], + xvimagesink->displaying_buffers[i].gem_name[1], + xvimagesink->displaying_buffers[i].gem_name[2]); + } else { + GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]", + i, xvimagesink->displaying_buffers[i].buffer, + xvimagesink->displaying_buffers[i].dmabuf_fd[0], + xvimagesink->displaying_buffers[i].dmabuf_fd[1], + xvimagesink->displaying_buffers[i].dmabuf_fd[2], + xvimagesink->displaying_buffers[i].gem_handle[0], + xvimagesink->displaying_buffers[i].gem_handle[1], + xvimagesink->displaying_buffers[i].gem_handle[2], + xvimagesink->displaying_buffers[i].gem_name[0], + xvimagesink->displaying_buffers[i].gem_name[1], + xvimagesink->displaying_buffers[i].gem_name[2]); + } + + /* set last added buffer index */ + xvimagesink->last_added_buffer_index = i; + GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i); + + /* unlock display buffer mutex */ + g_mutex_unlock(xvimagesink->display_buffer_lock); + + /* get current time */ + gettimeofday(&xvimagesink->request_time[i], NULL); + return; + } + } + + /* decrease displaying buffer count */ + xvimagesink->displaying_buffer_count--; + + /* unlock display buffer mutex */ + g_mutex_unlock(xvimagesink->display_buffer_lock); + + GST_ERROR("should not be reached here. buffer slot is FULL..."); + + return; +} + + +static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name) +{ + int i = 0; + int j = 0; + + if (!xvimagesink || !gem_name) { + GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name); + return; + } + + /* lock display buffer mutex */ + g_mutex_lock(xvimagesink->display_buffer_lock); + + if (xvimagesink->displaying_buffer_count == 0) { + GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer"); + /* unlock display buffer mutex */ + g_mutex_unlock(xvimagesink->display_buffer_lock); + return; + } + + GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d", + gem_name[0], gem_name[1], gem_name[2], + xvimagesink->displaying_buffer_count); + + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] && + xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] && + xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) { + struct timeval current_time; + + /* get current time to calculate displaying time */ + gettimeofday(¤t_time, NULL); + + GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us", + (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \ + (current_time.tv_usec - xvimagesink->request_time[i].tv_usec)); + + if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) { + xvimagesink->displayed_buffer_count++; + GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]", + xvimagesink->displayed_buffer_count, + i, xvimagesink->displaying_buffers[i].buffer, + xvimagesink->displaying_buffers[i].gem_handle[0], + xvimagesink->displaying_buffers[i].gem_handle[1], + xvimagesink->displaying_buffers[i].gem_handle[2], + xvimagesink->displaying_buffers[i].gem_name[0], + xvimagesink->displaying_buffers[i].gem_name[1], + xvimagesink->displaying_buffers[i].gem_name[2]); + } else { + GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]", + i, xvimagesink->displaying_buffers[i].buffer, + xvimagesink->displaying_buffers[i].gem_handle[0], + xvimagesink->displaying_buffers[i].gem_handle[1], + xvimagesink->displaying_buffers[i].gem_handle[2], + xvimagesink->displaying_buffers[i].gem_name[0], + xvimagesink->displaying_buffers[i].gem_name[1], + xvimagesink->displaying_buffers[i].gem_name[2]); + } + + /* decrease displaying buffer count */ + xvimagesink->displaying_buffer_count--; + + /* decrease ref count */ + xvimagesink->displaying_buffers[i].ref_count--; + + if (xvimagesink->displaying_buffers[i].ref_count > 0) { + GST_WARNING("ref count not zero[%d], skip close gem handle", + xvimagesink->displaying_buffers[i].ref_count); + break; + } + + /* release flush buffer */ + if (xvimagesink->flush_buffer) { + if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] && + xvimagesink->flush_buffer->gem_name[1] == gem_name[1] && + xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) { + _release_flush_buffer(xvimagesink); + } + } + + for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) { + if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) { + drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j])); + } + xvimagesink->displaying_buffers[i].gem_name[j] = 0; + xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0; + xvimagesink->displaying_buffers[i].bo[j] = NULL; + } + + /* reset last_added_buffer_index */ + if (xvimagesink->displaying_buffer_count < 1) { + xvimagesink->last_added_buffer_index = -1; + GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d", + xvimagesink->displaying_buffer_count); + } + + if (xvimagesink->displaying_buffers[i].buffer) { + gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer); + xvimagesink->displaying_buffers[i].buffer = NULL; + } else { + GST_WARNING("no buffer to unref"); + } + break; + } + } + + /* unlock display buffer mutex */ + g_mutex_unlock(xvimagesink->display_buffer_lock); + + return; +} + + +static int _is_connected_to_external_display(GstXvImageSink *xvimagesink) +{ + Atom type_ret = 0; + int i = 0; + int ret = 0; + int size_ret = 0; + unsigned long num_ret = 0; + unsigned long bytes = 0; + unsigned char *prop_ret = NULL; + unsigned int data = 0; + int (*handler) (Display *, XErrorEvent *) = NULL; + Atom atom_output_external; + + atom_output_external = XInternAtom(xvimagesink->xcontext->disp, + "XV_OUTPUT_EXTERNAL", False); + if (atom_output_external != None) { + /* set error handler */ + error_caught = FALSE; + handler = XSetErrorHandler(gst_xvimagesink_handle_xerror); + + ret = XGetWindowProperty(xvimagesink->xcontext->disp, + xvimagesink->xwindow->win, + atom_output_external, 0, 0x7fffffff, + False, XA_CARDINAL, &type_ret, &size_ret, + &num_ret, &bytes, &prop_ret); + XSync(xvimagesink->xcontext->disp, FALSE); + if (ret != Success || error_caught) { + GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed"); + if (prop_ret) { + XFree(prop_ret); + } + if (error_caught) { + GST_WARNING_OBJECT(xvimagesink, "error caught in XGetWindowProperty()"); + } + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } + return False; + } + + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } + + if (!num_ret) { + GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed"); + if (prop_ret) { + XFree(prop_ret); + } + return False; + } + + if (prop_ret) { + switch (size_ret) { + case 8: + for (i = 0 ; i < num_ret ; i++) { + (&data)[i] = prop_ret[i]; + } + break; + case 16: + for (i = 0 ; i < num_ret ; i++) { + ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i]; + } + break; + case 32: + for (i = 0 ; i < num_ret ; i++) { + ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i]; + } + break; + } + XFree(prop_ret); + prop_ret = NULL; + + GST_WARNING_OBJECT(xvimagesink, "external display %d", data); + + return (int)data; + } else { + GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL"); + return False; + } + } else { + GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed"); + } + + return False; +} #endif /* GST_EXT_XV_ENHANCEMENT */ /* This function handles a GstXWindow creation @@ -1473,7 +2877,7 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, XGCValues values; #ifdef GST_EXT_XV_ENHANCEMENT XSetWindowAttributes win_attr; - XWindowAttributes root_attr; + XWindowAttributes root_attr = {0 , }; #endif /* GST_EXT_XV_ENHANCEMENT */ g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); @@ -1492,7 +2896,8 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, xvimagesink->render_rect.h = xwindow->height = width; } - XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr); + if(!xvimagesink->is_pixmap) + XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr); if (xwindow->width > root_attr.width) { GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].", @@ -1521,7 +2926,8 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, /* Make window manager not to change window size as Full screen */ win_attr.override_redirect = True; - XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr); + if(!xvimagesink->is_pixmap) + XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr); #else /* GST_EXT_XV_ENHANCEMENT */ xvimagesink->render_rect.w = width; xvimagesink->render_rect.h = height; @@ -1546,10 +2952,17 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, if (xvimagesink->handle_events) { Atom wm_delete; - +#ifdef GST_EXT_XV_ENHANCEMENT + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask); + XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask); +#else XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); +#endif + /* Tell the window manager we'd like delete client messages instead of * being killed */ @@ -1607,12 +3020,35 @@ gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink, g_free (xwindow); } +#ifdef GST_EXT_XV_ENHANCEMENT +/* This function destroys a GstXWindow */ +static void +gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink, + GstXPixmap * xpixmap) +{ + g_return_if_fail (xpixmap != NULL); + g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); + + g_mutex_lock (xvimagesink->x_lock); + + XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0); + + XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc); + + XSync (xvimagesink->xcontext->disp, FALSE); + + g_mutex_unlock (xvimagesink->x_lock); + + g_free (xpixmap); +} +#endif /* GST_EXT_XV_ENHANCEMENT */ + static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink) { #ifdef GST_EXT_XV_ENHANCEMENT Window root_window, child_window; - XWindowAttributes root_attr; + XWindowAttributes root_attr = {0 , }; int cur_win_x = 0; int cur_win_y = 0; @@ -1644,18 +3080,21 @@ gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink) xvimagesink->xwindow->height = cur_win_height; /* Get absolute coordinates of current window */ - XTranslateCoordinates( xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, - root_window, - 0, 0, - &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y - &child_window ); + if(!xvimagesink->is_pixmap) { + XTranslateCoordinates( xvimagesink->xcontext->disp, + xvimagesink->xwindow->win, + root_window, + 0, 0, + &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y + &child_window ); + } xvimagesink->xwindow->x = cur_win_x; xvimagesink->xwindow->y = cur_win_y; /* Get size of root window == size of screen */ - XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr); + if(!xvimagesink->is_pixmap) + XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr); xvimagesink->scr_w = root_attr.width; xvimagesink->scr_h = root_attr.height; @@ -1665,6 +3104,16 @@ gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink) xvimagesink->render_rect.w = cur_win_width; xvimagesink->render_rect.h = cur_win_height; } + if (xvimagesink->scr_w != xvimagesink->xwindow->width || + xvimagesink->scr_h != xvimagesink->xwindow->height) { + xvimagesink->is_multi_window = TRUE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window); + GST_INFO_OBJECT(xvimagesink, "It may be multi-window scenario"); + } else { + xvimagesink->is_multi_window = FALSE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window); + GST_INFO_OBJECT(xvimagesink, "It may be full-window scenario"); + } GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d", xvimagesink->scr_w, xvimagesink->scr_h, @@ -1693,14 +3142,24 @@ static void gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink, GstXWindow * xwindow) { +#ifdef GST_EXT_XV_ENHANCEMENT + if (xvimagesink->is_subpicture_format) + return; +#endif g_return_if_fail (xwindow != NULL); g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); g_mutex_lock (xvimagesink->x_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo"); +#endif /* GST_EXT_XV_ENHANCEMENT */ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xwindow->win); -#ifndef GST_EXT_XV_ENHANCEMENT +#ifdef GST_EXT_XV_ENHANCEMENT +#if 0 + /* NOTE : it should be enabled in pixmap buffer case, + if we can check whether if it is a pixmap or a window by X API */ /* Preview area is not updated before other UI is updated in the screen. */ XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, xvimagesink->xcontext->black); @@ -1708,6 +3167,7 @@ gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink, XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, xvimagesink->render_rect.x, xvimagesink->render_rect.y, xvimagesink->render_rect.w, xvimagesink->render_rect.h); +#endif #endif /* GST_EXT_XV_ENHANCEMENT */ XSync (xvimagesink->xcontext->disp, FALSE); @@ -1798,12 +3258,21 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); +#ifdef GST_EXT_XV_ENHANCEMENT + GST_LOG("check x event"); + Atom sc_status_atom = XInternAtom (xvimagesink->xcontext->disp, STR_ATOM_SCRNCONF_STATUS, FALSE); + Atom external_atom = XInternAtom (xvimagesink->xcontext->disp, "XV_OUTPUT_EXTERNAL", FALSE); +#endif /* GST_EXT_XV_ENHANCEMENT */ + /* Handle Interaction, produces navigation events */ /* We get all pointer motion events, only the last position is interesting. */ g_mutex_lock (xvimagesink->flow_lock); g_mutex_lock (xvimagesink->x_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + if (xvimagesink->xcontext->disp) { +#endif //GST_EXT_XV_ENHANCEMENT while (XCheckWindowEvent (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, PointerMotionMask, &e)) { g_mutex_unlock (xvimagesink->x_lock); @@ -1821,6 +3290,9 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_mutex_lock (xvimagesink->flow_lock); g_mutex_lock (xvimagesink->x_lock); } +#ifdef GST_EXT_XV_ENHANCEMENT + } +#endif //GST_EXT_XV_ENHANCEMENT if (pointer_moved) { g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->flow_lock); @@ -1891,7 +3363,6 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_mutex_lock (xvimagesink->flow_lock); g_mutex_lock (xvimagesink->x_lock); } - /* Handle Expose */ while (XCheckWindowEvent (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { @@ -1902,9 +3373,12 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) case ConfigureNotify: g_mutex_unlock (xvimagesink->x_lock); #ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT (xvimagesink, "Call gst_xvimagesink_xwindow_update_geometry!"); + GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!"); #endif /* GST_EXT_XV_ENHANCEMENT */ gst_xvimagesink_xwindow_update_geometry (xvimagesink); +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!"); +#endif /* GST_EXT_XV_ENHANCEMENT */ g_mutex_lock (xvimagesink->x_lock); configured = TRUE; break; @@ -1917,104 +3391,333 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->flow_lock); - gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); + gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); + + g_mutex_lock (xvimagesink->flow_lock); + g_mutex_lock (xvimagesink->x_lock); + } + + /* Handle Display events */ + while (XPending (xvimagesink->xcontext->disp)) { + XNextEvent (xvimagesink->xcontext->disp, &e); + switch (e.type) { + case ClientMessage:{ +#ifdef GST_EXT_XV_ENHANCEMENT + XClientMessageEvent *cme = (XClientMessageEvent *)&e; + Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False); + Atom qp_state_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_STATE", False); + Atom qp_on_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_ON", False); + Atom qp_off_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_OFF", False); +#endif /* GST_EXT_XV_ENHANCEMENT */ + Atom wm_delete; + +#ifdef GST_EXT_XV_ENHANCEMENT + GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom); + if (cme->message_type == buffer_atom) { + unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, }; + + GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d", + cme->data.l[0], cme->data.l[1]); + + gem_name[0] = cme->data.l[0]; + gem_name[1] = cme->data.l[1]; + + _remove_displaying_buffer(xvimagesink, gem_name); + break; + } else if (cme->message_type == sc_status_atom) { + int stat = cme->data.s[0]; + if (stat == UTILX_SCRNCONF_STATUS_NULL) { + GST_WARNING ("get UTILX_SCRNCONF_STATUS_NULL event\n"); + check_hdmi_connected(xvimagesink); + } else if (stat == UTILX_SCRNCONF_STATUS_CONNECT) { + GST_WARNING ("get UTILX_SCRNCONF_STATUS_CONNECT event\n"); + check_hdmi_connected(xvimagesink); + } else if (stat == UTILX_SCRNCONF_STATUS_ACTIVE) { + GST_WARNING ("get UTILX_SCRNCONF_STATUS_ACTIVE event\n"); + g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_HDMI_ACTIVE); + check_hdmi_connected(xvimagesink); + } else { + GST_INFO ("Wrong status\n"); + } + break; + } else if (cme->message_type == qp_state_atom) { + if ((Atom) cme->data.l[0] == qp_on_atom) { + /* quick panel on */ + GST_WARNING_OBJECT(xvimagesink, "quick panel is ON"); + xvimagesink->is_quick_panel_on = TRUE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", TRUE); + } else if ((Atom) cme->data.l[0] == qp_off_atom) { + /* quick panel off */ + GST_WARNING_OBJECT(xvimagesink, "quick panel is OFF"); + xvimagesink->is_quick_panel_on = FALSE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", FALSE); + } + break; + } +#endif /* GST_EXT_XV_ENHANCEMENT */ + + wm_delete = XInternAtom (xvimagesink->xcontext->disp, + "WM_DELETE_WINDOW", True); + if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { + /* Handle window deletion by posting an error on the bus */ + GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, + ("Output window was closed"), (NULL)); + + g_mutex_unlock (xvimagesink->x_lock); + gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); + xvimagesink->xwindow = NULL; + g_mutex_lock (xvimagesink->x_lock); + } + break; + } +#ifdef GST_EXT_XV_ENHANCEMENT + case VisibilityNotify: + if (xvimagesink->xwindow && + (e.xvisibility.window == xvimagesink->xwindow->win)) { + if (e.xvisibility.state == VisibilityFullyObscured) { + Atom atom_stream; + + GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED"); + + xvimagesink->is_hided = TRUE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", TRUE); + if (!_is_connected_to_external_display(xvimagesink)) { + GST_WARNING_OBJECT(xvimagesink, "no external display, calling XvStopVideo()"); + XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win); + XSync(xvimagesink->xcontext->disp, FALSE); + } else { + if (GST_STATE(xvimagesink) == GST_STATE_PLAYING || xvimagesink->keep_external_fullscreen_prev) { + GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip XvStopVideo()"); + } else { + GST_WARNING_OBJECT(xvimagesink, "external display is enabled, but not in the middle of playing, calling XvStopVideo()"); + XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win); + XSync(xvimagesink->xcontext->disp, FALSE); + } + } + } else { + GST_INFO_OBJECT(xvimagesink, "current window is SHOWN"); + + if (xvimagesink->is_hided) { + g_mutex_unlock(xvimagesink->x_lock); + g_mutex_unlock(xvimagesink->flow_lock); + + xvimagesink->is_hided = FALSE; + g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", FALSE); + gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink)); + + g_mutex_lock(xvimagesink->flow_lock); + g_mutex_lock(xvimagesink->x_lock); + } else { + GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event"); + } + } + } + break; + + case PropertyNotify: + { + XPropertyEvent *noti = (XPropertyEvent *)&e; + if(xvimagesink->xwindow) { + if (noti->window == xvimagesink->xwindow->win && noti->atom == external_atom) { + int value = 0; + get_window_prop_card32_property (xvimagesink->xcontext->disp, + xvimagesink->xwindow->win, + external_atom, XA_CARDINAL, + (unsigned int*)&value, 1); + if (value) { + // If value is 1, video will be displayed only on external display. + // video won't be displayed on LCD. + g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_UNKNOWN_ACTIVE); + if(xvimagesink->external_width==0 && xvimagesink->external_height==0) { + xvimagesink->external_width = 1920; + xvimagesink->external_height = 1080; + GST_WARNING("connected unknown external display"); + } + } else { + g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_NULL); //NULL + if(xvimagesink->external_width!=0 || xvimagesink->external_height!=0) { + xvimagesink->external_width = 0; + xvimagesink->external_height = 0; + GST_WARNING("disconnected external display"); + } + } + + g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height); + GST_INFO ("external device : %s\n", (value)?"on":"off"); + } + } + break; + } + +#endif /* GST_EXT_XV_ENHANCEMENT */ + default: + break; + } + } + g_mutex_unlock (xvimagesink->x_lock); + g_mutex_unlock (xvimagesink->flow_lock); +} +#ifdef GST_EXT_XV_ENHANCEMENT +static int +get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type, + unsigned int *val, unsigned int len) +{ + unsigned char* prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + unsigned int i; + int num; + int ret; + int (*handler) (Display *, XErrorEvent *) = NULL; + + prop_ret = NULL; + + /* set error handler */ + error_caught = FALSE; + handler = XSetErrorHandler(gst_xvimagesink_handle_xerror); + + ret = XGetWindowProperty(dpy, win, atom, 0, 0x7fffffff, False, + type, &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret); + XSync(dpy, FALSE); + if (ret != Success || error_caught) { + GST_WARNING("XGetWindowProperty failed [%d, %d]", ret, error_caught); + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } + return -1; + } + + if (handler) { + error_caught = FALSE; + XSetErrorHandler(handler); + } + + if (type_ret != type || format_ret != 32) + num = -1; + else if (num_ret == 0 || !prop_ret) + num = 0; + else + { + if (num_ret < len) + len = num_ret; + for (i = 0; i < len; i++) + val[i] = ((unsigned long *)prop_ret)[i]; + num = len; + } + + if (prop_ret) + XFree(prop_ret); - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); + return num; +} + +static void check_hdmi_connected(GstXvImageSink *xvimagesink) +{ + char *str_output = NULL; + char *str_resolution = NULL; + int external[2]; + int cnt = 0; + char** list = NULL; + char** walk = NULL; + + UtilxScrnConf *scrnconf = utilx_scrnconf_allocate(); + if (!scrnconf) + { + GST_WARNING ("fail to allocate scrnconf"); + return; } + utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf); - /* Handle Display events */ - while (XPending (xvimagesink->xcontext->disp)) { - XNextEvent (xvimagesink->xcontext->disp, &e); + str_output = scrnconf->str_output; - switch (e.type) { - case ClientMessage:{ -#ifdef GST_EXT_XV_ENHANCEMENT - int active_pid, deactive_pid; - Atom active_win_atom; - Atom deactive_win_atom; - Atom atom_stream; -#endif /* GST_EXT_XV_ENHANCEMENT */ - Atom wm_delete; + if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT) + { + GST_INFO("CONNECT"); + } + else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE) + { + GST_INFO("ACTIVE"); - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { - /* Handle window deletion by posting an error on the bus */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, - ("Output window was closed"), (NULL)); + list = g_strsplit(scrnconf->str_resolution, "x", 2); - g_mutex_unlock (xvimagesink->x_lock); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - g_mutex_lock (xvimagesink->x_lock); - } -#ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT( xvimagesink, "message type : %d", e.xclient.message_type ); + if (!list) + { + if (scrnconf) + utilx_scrnconf_free (scrnconf); + return; + } + for(walk = list; *walk; walk++) + { + external[cnt++] = atoi(*walk); + } + if (cnt!=2) { + GST_WARNING("data error"); + if(scrnconf) + utilx_scrnconf_free (scrnconf); + g_strfreev(list); + return; + } else { + xvimagesink->external_width = external[0]; + xvimagesink->external_height = external[1]; + g_strfreev(list); + } + GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height); + g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height); + } + else + { + GST_INFO("NULL"); + } - active_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_ACTIVATE_WINDOW", False); - deactive_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_DEACTIVATE_WINDOW", False); + str_resolution = scrnconf->str_resolution; - if (!active_win_atom || !deactive_win_atom) { - GST_WARNING_OBJECT( xvimagesink, "Can NOT get active[%d] or deactive[%d] win atom", - active_win_atom, deactive_win_atom ); - } else { - if (e.xclient.message_type == deactive_win_atom) { - /* Window is DEACTIVATED */ - /* Get pid of activated/deactivated window */ - active_pid = e.xclient.data.l[1]; - deactive_pid = e.xclient.data.l[3]; - - if (active_pid != deactive_pid) { - GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window DEACTIVATED" ); - - xvimagesink->is_hided = TRUE; - atom_stream = XInternAtom( xvimagesink->xcontext->disp, - "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False ); - if (atom_stream != None) { - if (XvSetPortAttribute(xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - atom_stream, 0 ) != Success) { - GST_WARNING_OBJECT( xvimagesink, "STREAM OFF failed" ); - } - XSync( xvimagesink->xcontext->disp, FALSE ); - } - } else { - GST_INFO_OBJECT( xvimagesink, "Window is DEACTIVATED, but same process. so Do not clear screen." ); - } - } else if (e.xclient.message_type == active_win_atom) { - /* Window is ACTIVATED */ - /* Get pid of activated/deactivated window */ - active_pid = e.xclient.data.l[1]; - deactive_pid = e.xclient.data.l[3]; + if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE) + { + GST_INFO("CLONE mode"); + } + else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED) + { + GST_INFO("EXTENDED mode"); + } + else + { + GST_INFO("NULL mode"); + } - if (active_pid != deactive_pid) { - GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window ACTIVATED" ); + GST_INFO ("[Display status] : %s, %s\n", str_output, str_resolution); - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); + if(scrnconf) + utilx_scrnconf_free (scrnconf); - xvimagesink->is_hided = FALSE; - gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); +} - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } else { - GST_INFO_OBJECT( xvimagesink, "Window is ACTIVATED, but same process. so Do not redraw screen." ); - } - } - } -#endif /* GST_EXT_XV_ENHANCEMENT */ - break; +static gboolean +check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name) +{ + int i = 0; + int count = 0; + + XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, &count); + if (attr) { + for (i = 0 ; i < count ; i++) { + if (!strcmp(attr[i].name, attr_name)) { + GST_INFO("%s[index %d] found", attr_name, i); + XFree(attr); + return TRUE; } - default: - break; } + XFree(attr); + } else { + GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed", + xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id); } - - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); + return FALSE; } +#endif //GST_EXT_XV_ENHANCEMENT static void gst_lookup_xv_port_from_adaptor (GstXContext * xcontext, @@ -2045,6 +3748,40 @@ gst_lookup_xv_port_from_adaptor (GstXContext * xcontext, } } +#ifdef GST_EXT_XV_ENHANCEMENT +static void +gst_lookup_xv_port_for_subtitle (GstXContext * xcontext, + XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors) +{ + int i; + if (!adaptors) + return; + for (i = 0; i < nb_adaptors; i++) + { + int min, max; + if (!(adaptors[i].type & XvOutputMask) || + !(adaptors[i].type & XvStillMask)) + continue; + min = adaptors[i].base_id; + max = adaptors[i].base_id + adaptors[i].num_ports; + for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++) + { + if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success) + { + GST_INFO ("========================================"); + GST_INFO ("XvGrabPort success : %ld", adaptors[adaptor_no].num_ports); + GST_INFO ("========================================"); + xcontext->xv_port_id = adaptors[adaptor_no].num_ports; + return; + } + GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports); + usleep(10000); + } + } +} +#endif + + /* This function generates a caps with all supported format by the first Xv grabable port we find. We store each one of the supported formats in a format list and append the format to a newly created caps that we return @@ -2085,7 +3822,7 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, xcontext->xv_port_id = 0; - GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors); + GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors); xcontext->adaptors = (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *)); @@ -2098,14 +3835,27 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, if (xvimagesink->adaptor_no >= 0 && xvimagesink->adaptor_no < xcontext->nb_adaptors) { /* Find xv port from user defined adaptor */ - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, - xvimagesink->adaptor_no); +#ifdef GST_EXT_XV_ENHANCEMENT + if(!xvimagesink->subpicture) +#endif + gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no); +#ifdef GST_EXT_XV_ENHANCEMENT + else + gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors); +#endif } if (!xcontext->xv_port_id) { /* Now search for an adaptor that supports XvImageMask */ for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) { - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); +#ifdef GST_EXT_XV_ENHANCEMENT + if(!xvimagesink->subpicture) +#endif + gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); +#ifdef GST_EXT_XV_ENHANCEMENT + else + gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors); +#endif xvimagesink->adaptor_no = i; } } @@ -2225,7 +3975,9 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, } XvFreeEncodingInfo (encodings); - +#ifdef GST_EXT_XV_ENHANCEMENT +if (!xvimagesink->subpicture) { +#endif /* We get all image formats supported by our port */ formats = XvListImageFormats (xcontext->disp, xcontext->xv_port_id, &nb_formats); @@ -2262,6 +4014,9 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, } format_caps = gst_caps_new_simple ("video/x-raw-rgb", +#ifdef GST_EXT_XV_ENHANCEMENT + "format", GST_TYPE_FOURCC, formats[i].id, +#endif /* GST_EXT_XV_ENHANCEMENT */ "endianness", G_TYPE_INT, endianness, "depth", G_TYPE_INT, fmt->depth, "bpp", G_TYPE_INT, fmt->bits_per_pixel, @@ -2324,6 +4079,9 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, ("No supported format found")); return NULL; } +#ifdef GST_EXT_XV_ENHANCEMENT +} //subpicture +#endif return caps; } @@ -2340,8 +4098,13 @@ gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink) if (xvimagesink->xwindow) { gst_xvimagesink_handle_xevents (xvimagesink); } + +#ifdef GST_EXT_XV_ENHANCEMENT + g_usleep (_EVENT_THREAD_CHECK_INTERVAL); +#else /* GST_EXT_XV_ENHANCEMENT */ /* FIXME: do we want to align this with the framerate or anything else? */ g_usleep (G_USEC_PER_SEC / 20); +#endif /* GST_EXT_XV_ENHANCEMENT */ GST_OBJECT_LOCK (xvimagesink); } @@ -2394,6 +4157,46 @@ gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink) } +#ifdef GST_EXT_XV_ENHANCEMENT +/** + * gst_xvimagesink_prepare_xid: + * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap. + * + * This will post a "prepare-xid" element message with video size and display size on the bus + * to give applications an opportunity to call + * gst_x_overlay_set_xwindow_id() before a plugin creates its own + * window or pixmap. + * + * This function should only be used by video overlay plugin developers. + */ +static void +gst_xvimagesink_prepare_xid (GstXOverlay * overlay) +{ + GstStructure *s; + GstMessage *msg; + + g_return_if_fail (overlay != NULL); + g_return_if_fail (GST_IS_X_OVERLAY (overlay)); + + GstXvImageSink *xvimagesink; + xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay)); + + GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)", + GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height); + + GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid"); + s = gst_structure_new ("prepare-xid", + "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink), + "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink), + "display-width", G_TYPE_INT, xvimagesink->xcontext->width, + "display-height", G_TYPE_INT, xvimagesink->xcontext->height, + NULL); + msg = gst_message_new_element (GST_OBJECT (overlay), s); + gst_element_post_message (GST_ELEMENT (overlay), msg); +} +#endif /* GST_EXT_XV_ENHANCEMENT */ + + /* This function calculates the pixel aspect ratio based on the properties * in the xcontext structure and stores it there. */ static void @@ -2403,6 +4206,9 @@ gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) {1, 1}, /* regular screen */ {16, 15}, /* PAL TV */ {11, 10}, /* 525 line Rec.601 video */ +#ifdef GST_EXT_XV_ENHANCEMENT + {44, 46}, /* Gear S Curved Display */ +#endif {54, 59}, /* 625 line Rec.601 video */ {64, 45}, /* 1280x1024 on 16:9 display */ {5, 3}, /* 1280x1024 on 4:3 display */ @@ -2461,7 +4267,7 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) GstXContext *xcontext = NULL; XPixmapFormatValues *px_formats = NULL; gint nb_formats = 0, i, j, N_attr; - XvAttribute *xv_attr; + XvAttribute *xv_attr = NULL; Atom prop_atom; const char *channels[4] = { "XV_HUE", "XV_SATURATION", "XV_BRIGHTNESS", "XV_CONTRAST" @@ -2475,7 +4281,6 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) g_mutex_lock (xvimagesink->x_lock); xcontext->disp = XOpenDisplay (xvimagesink->display_name); - if (!xcontext->disp) { g_mutex_unlock (xvimagesink->x_lock); g_free (xcontext); @@ -2484,6 +4289,22 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) return NULL; } +#ifdef GST_EXT_XV_ENHANCEMENT + { + int i = 0; + for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) { + if (g_display_id[i] == NULL) { + g_display_id[i] = xcontext->disp; + GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp); + break; + } + } + if (i == MAX_DISPLAY_IN_XVIMAGESINK) { + GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i); + } + } +#endif + xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); xcontext->screen_num = DefaultScreen (xcontext->disp); xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); @@ -2505,6 +4326,16 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); if (!px_formats) { +#ifdef GST_EXT_XV_ENHANCEMENT + { + int i = 0; + for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) { + if (g_display_id[i] == xcontext->disp) { + g_display_id[i] = NULL; + } + } + } +#endif XCloseDisplay (xcontext->disp); g_mutex_unlock (xvimagesink->x_lock); g_free (xcontext->par); @@ -2542,7 +4373,21 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext); - if (!xcontext->caps) { + if (!xcontext->caps +#ifdef GST_EXT_XV_ENHANCEMENT + && !xvimagesink->subpicture +#endif + ) { +#ifdef GST_EXT_XV_ENHANCEMENT + { + int i = 0; + for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) { + if (g_display_id[i] == xcontext->disp) { + g_display_id[i] = NULL; + } + } + } +#endif XCloseDisplay (xcontext->disp); g_mutex_unlock (xvimagesink->x_lock); g_free (xcontext->par); @@ -2551,21 +4396,26 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) return NULL; } #ifdef HAVE_XSHM - /* Search for XShm extension support */ - if (XShmQueryExtension (xcontext->disp) && - gst_xvimagesink_check_xshm_calls (xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("xvimagesink is using XShm extension"); - } else +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->subpicture) { +#endif //GST_EXT_XV_ENHANCEMENT + /* Search for XShm extension support */ + if (XShmQueryExtension (xcontext->disp) && + gst_xvimagesink_check_xshm_calls (xcontext)) { + xcontext->use_xshm = TRUE; + GST_DEBUG ("xvimagesink is using XShm extension"); + } else #endif /* HAVE_XSHM */ - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("xvimagesink is not using XShm extension"); - } - - xv_attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &N_attr); + { + xcontext->use_xshm = FALSE; + GST_DEBUG ("xvimagesink is not using XShm extension"); + } + xv_attr = XvQueryPortAttributes (xcontext->disp, + xcontext->xv_port_id, &N_attr); +#ifdef GST_EXT_XV_ENHANCEMENT + } +#endif //GST_EXT_XV_ENHANCEMENT /* Generate the channels list */ for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { @@ -2616,12 +4466,17 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) } } } - +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->subpicture) { +#endif if (xv_attr) XFree (xv_attr); - #ifdef GST_EXT_XV_ENHANCEMENT - set_display_mode(xcontext, xvimagesink->display_mode); + } + if(!xvimagesink->subpicture) { + set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode); + set_csc_range(xcontext, xvimagesink->csc_range); + } #endif /* GST_EXT_XV_ENHANCEMENT */ g_mutex_unlock (xvimagesink->x_lock); @@ -2634,7 +4489,7 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) static void gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) { - GList *formats_list, *channels_list; + GList *formats_list, *channels_list = NULL; GstXContext *xcontext; gint i = 0; @@ -2652,7 +4507,9 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) GST_OBJECT_UNLOCK (xvimagesink); - +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->subpicture) { +#endif formats_list = xcontext->formats_list; while (formats_list) { @@ -2667,7 +4524,9 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) g_list_free (xcontext->formats_list); channels_list = xcontext->channels_list; - +#ifdef GST_EXT_XV_ENHANCEMENT + } +#endif while (channels_list) { GstColorBalanceChannel *channel = channels_list->data; @@ -2696,8 +4555,17 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); +#ifdef GST_EXT_XV_ENHANCEMENT + { + int i = 0; + for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) { + if (g_display_id[i] == xcontext->disp) { + g_display_id[i] = NULL; + } + } + } +#endif XCloseDisplay (xcontext->disp); - g_mutex_unlock (xvimagesink->x_lock); g_free (xcontext); @@ -2753,10 +4621,13 @@ gst_xvimagesink_getcaps (GstBaseSink * bsink) GstXvImageSink *xvimagesink; xvimagesink = GST_XVIMAGESINK (bsink); - - if (xvimagesink->xcontext) + if (xvimagesink->xcontext +#ifdef GST_EXT_XV_ENHANCEMENT + && !xvimagesink->subpicture +#endif +) { return gst_caps_ref (xvimagesink->xcontext->caps); - + } return gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (xvimagesink))); @@ -2779,7 +4650,15 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) const GValue *fps; guint num, den; #ifdef GST_EXT_XV_ENHANCEMENT - gboolean enable_last_buffer; + gboolean subtitle; + gchar *str_in = gst_caps_to_string(caps); + if(str_in == NULL) { + GST_ERROR("gst_caps_to_string() returns NULL..."); + }else{ + GST_INFO("In setcaps. incaps:%s", str_in); + g_free (str_in); + str_in = NULL; + } #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */ xvimagesink = GST_XVIMAGESINK (bsink); @@ -2788,7 +4667,11 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps); - if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)) + if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps) +#ifdef GST_EXT_XV_ENHANCEMENT + && !xvimagesink->subpicture +#endif + ) goto incompatible_caps; structure = gst_caps_get_structure (caps, 0); @@ -2796,7 +4679,13 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) ret &= gst_structure_get_int (structure, "height", &video_height); fps = gst_structure_get_value (structure, "framerate"); ret &= (fps != NULL); - +#ifdef GST_EXT_XV_ENHANCEMENT + if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture) + { + xvimagesink->is_subpicture_format = TRUE; + GST_LOG("It is type of subpicture and subtitle."); + } +#endif if (!ret) goto incomplete_caps; @@ -2804,16 +4693,19 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) xvimagesink->aligned_width = video_width; xvimagesink->aligned_height = video_height; - /* get enable-last-buffer */ - g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL); - GST_INFO_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer); - - /* flush if enable-last-buffer is TRUE */ - if (enable_last_buffer) { - GST_INFO_OBJECT(xvimagesink, "flush last-buffer"); - g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL); - g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL); +#ifdef GST_EXT_ENABLE_HEVC + /*get combine prop of hevc*/ + if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data))) + { + GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data); + } + else + { + /*Not need to combine data, just directly copy*/ + xvimagesink->need_combine_data = 0; } +#endif + _remove_last_buffer(xvimagesink); #endif /* GST_EXT_XV_ENHANCEMENT */ xvimagesink->fps_n = gst_value_get_fraction_numerator (fps); @@ -2821,11 +4713,15 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) xvimagesink->video_width = video_width; xvimagesink->video_height = video_height; - +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->subpicture) { +#endif im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); if (im_format == -1) goto invalid_format; - +#ifdef GST_EXT_XV_ENHANCEMENT + } +#endif /* get aspect ratio from caps if it's present, and * convert video width and height to a display width and height * using wd / hd = wv / hv * PARv / PARd */ @@ -2902,23 +4798,37 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) /* Notify application to set xwindow id now */ g_mutex_lock (xvimagesink->flow_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) { + g_mutex_unlock (xvimagesink->flow_lock); + gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink)); +#else if (!xvimagesink->xwindow) { g_mutex_unlock (xvimagesink->flow_lock); gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink)); +#endif } else { g_mutex_unlock (xvimagesink->flow_lock); } +#ifdef GST_EXT_XV_ENHANCEMENT +if (!xvimagesink->is_subpicture_format) { +#endif + /* Creating our window and our image with the display size in pixels */ + if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 || + GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0) + goto no_display_size; - /* Creating our window and our image with the display size in pixels */ - if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0) - goto no_display_size; - - g_mutex_lock (xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { - xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink, - GST_VIDEO_SINK_WIDTH (xvimagesink), - GST_VIDEO_SINK_HEIGHT (xvimagesink)); + g_mutex_lock (xvimagesink->flow_lock); +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) { + GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case"); +#else + if (!xvimagesink->xwindow) { +#endif + xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink, + GST_VIDEO_SINK_WIDTH (xvimagesink), + GST_VIDEO_SINK_HEIGHT (xvimagesink)); + } } /* After a resize, we want to redraw the borders in case the new frame size @@ -2930,7 +4840,8 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) if ((xvimagesink->xvimage) && ((im_format != xvimagesink->xvimage->im_format) || (video_width != xvimagesink->xvimage->width) || - (video_height != xvimagesink->xvimage->height))) { + (video_height != xvimagesink->xvimage->height)) && + (!xvimagesink->subpicture)) { GST_DEBUG_OBJECT (xvimagesink, "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (xvimagesink->xvimage->im_format), @@ -2940,6 +4851,12 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) xvimagesink->xvimage = NULL; } +#ifdef GST_EXT_XV_ENHANCEMENT + /* In case of starting player with connecting external display, we have to check status. + * It will be unconditionally executed. */ + if(!xvimagesink->is_subpicture_format) + check_hdmi_connected(xvimagesink); +#endif g_mutex_unlock (xvimagesink->flow_lock); return TRUE; @@ -2974,7 +4891,9 @@ no_display_size: ("Error calculating the output display ratio of the video.")); return FALSE; } +#ifdef GST_EXT_XV_ENHANCEMENT } +#endif static GstStateChangeReturn gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) @@ -2990,6 +4909,9 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("NULL_TO_READY start"); +#endif /* GST_EXT_XV_ENHANCEMENT */ /* Initializing the XContext */ if (xvimagesink->xcontext == NULL) { xcontext = gst_xvimagesink_xcontext_get (xvimagesink); @@ -3013,32 +4935,39 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); gst_xvimagesink_update_colorbalance (xvimagesink); gst_xvimagesink_manage_event_thread (xvimagesink); +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("NULL_TO_READY done"); +#endif /* GST_EXT_XV_ENHANCEMENT */ break; case GST_STATE_CHANGE_READY_TO_PAUSED: +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("READY_TO_PAUSED start"); +#endif /* GST_EXT_XV_ENHANCEMENT */ g_mutex_lock (xvimagesink->pool_lock); xvimagesink->pool_invalid = FALSE; g_mutex_unlock (xvimagesink->pool_lock); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: #ifdef GST_EXT_XV_ENHANCEMENT - g_mutex_lock (xvimagesink->x_lock); - atom_preemption = XInternAtom( xvimagesink->xcontext->disp, - "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False ); - if (atom_preemption != None) { - if (XvSetPortAttribute(xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - atom_preemption, 1 ) != Success) { - GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption); - } - XSync (xvimagesink->xcontext->disp, FALSE); - } - g_mutex_unlock (xvimagesink->x_lock); + GST_WARNING("READY_TO_PAUSED done"); +#endif /* GST_EXT_XV_ENHANCEMENT */ + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: +#ifdef GST_EXT_XV_ENHANCEMENT + if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING)) + GST_WARNING("vconf set fail"); + GST_WARNING("PAUSED_TO_PLAYING done"); + xvimagesink->is_during_seek = FALSE; + xvimagesink->keep_external_fullscreen_prev = FALSE; #endif /* GST_EXT_XV_ENHANCEMENT */ break; case GST_STATE_CHANGE_PAUSED_TO_READY: +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("PAUSED_TO_READY start"); +#endif /* GST_EXT_XV_ENHANCEMENT */ g_mutex_lock (xvimagesink->pool_lock); xvimagesink->pool_invalid = TRUE; g_mutex_unlock (xvimagesink->pool_lock); +#ifdef GST_EXT_XV_ENHANCEMENT +#endif /* GST_EXT_XV_ENHANCEMENT */ break; default: break; @@ -3049,29 +4978,119 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: #ifdef GST_EXT_XV_ENHANCEMENT - xvimagesink->rotate_changed = TRUE; + GST_WARNING("PLAYING_TO_PAUSED start"); + g_mutex_lock (xvimagesink->flow_lock); + /* init displayed buffer count */ + xvimagesink->displayed_buffer_count = 0; + g_mutex_lock (xvimagesink->x_lock); - atom_preemption = XInternAtom( xvimagesink->xcontext->disp, - "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False ); - if (atom_preemption != None) { - if (XvSetPortAttribute(xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - atom_preemption, 0 ) != Success) { - GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption); - } - XSync (xvimagesink->xcontext->disp, FALSE); + if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) { + GST_WARNING_OBJECT(xvimagesink, "release external display mode"); + XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, + xvimagesink->xwindow->win); + XSync(xvimagesink->xcontext->disp, FALSE); + xvimagesink->skip_frame_due_to_external_dev = TRUE; + } + if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture) + && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) { + GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture); + XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture); + XSync(xvimagesink->xcontext->disp, FALSE); } g_mutex_unlock (xvimagesink->x_lock); + g_mutex_unlock (xvimagesink->flow_lock); + if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED)) + GST_WARNING("vconf set fail"); + GST_WARNING("PLAYING_TO_PAUSED done"); #endif /* GST_EXT_XV_ENHANCEMENT */ break; case GST_STATE_CHANGE_PAUSED_TO_READY: +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p", + xvimagesink->is_zero_copy_format, + xvimagesink->enable_flush_buffer, + xvimagesink->secure_path, + xvimagesink->get_pixmap_cb); + + if ((xvimagesink->enable_flush_buffer == FALSE || + xvimagesink->secure_path == SECURE_PATH_ON) && + xvimagesink->xcontext && xvimagesink->xwindow) { + GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer"); + g_mutex_lock(xvimagesink->x_lock); + XvStopVideo(xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + xvimagesink->xwindow->win); + XSync(xvimagesink->xcontext->disp, FALSE); + g_mutex_unlock(xvimagesink->x_lock); + _remove_last_buffer(xvimagesink); + } else if (xvimagesink->is_zero_copy_format && + xvimagesink->xvimage && + xvimagesink->xvimage->xvimage && + !xvimagesink->get_pixmap_cb) { + if (gst_xvimagesink_make_flush_buffer(xvimagesink)) { + int i = 0; + XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data; + memset(img_data, 0x0, sizeof(XV_DATA)); + XV_INIT_DATA(img_data); + + img_data->bo[0] = xvimagesink->flush_buffer->bo[0]; + img_data->bo[1] = xvimagesink->flush_buffer->bo[1]; + img_data->bo[2] = xvimagesink->flush_buffer->bo[2]; + + gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage); + + GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done"); + + /* check whether putimage is succeeded or not */ + g_mutex_lock(xvimagesink->display_buffer_lock); + + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) { + if ((img_data->dmabuf_fd[0] > 0 && + xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] && + xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] && + xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) || + (img_data->bo[0] && + xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] && + xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] && + xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) { + GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers"); + break; + } + } + } + + if (i >= DISPLAYING_BUFFERS_MAX_NUM) { + GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers"); + _release_flush_buffer(xvimagesink); + } else { + _remove_last_buffer(xvimagesink); + } + + g_mutex_unlock(xvimagesink->display_buffer_lock); + } + } +#endif /* GST_EXT_XV_ENHANCEMENT */ xvimagesink->fps_n = 0; xvimagesink->fps_d = 1; GST_VIDEO_SINK_WIDTH (xvimagesink) = 0; GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0; +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("PAUSED_TO_READY done"); +#endif /* GST_EXT_XV_ENHANCEMENT */ break; case GST_STATE_CHANGE_READY_TO_NULL: +#ifdef GST_EXT_XV_ENHANCEMENT + GST_WARNING("READY_TO_NULL start"); +#endif /* GST_EXT_XV_ENHANCEMENT */ gst_xvimagesink_reset (xvimagesink); +#ifdef GST_EXT_XV_ENHANCEMENT + /* close drm */ + drm_fini(xvimagesink); + /* init displaying_buffer_count */ + xvimagesink->displaying_buffer_count = 0; + GST_WARNING("READY_TO_NULL done"); +#endif /* GST_EXT_XV_ENHANCEMENT */ break; default: break; @@ -3102,15 +5121,178 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, } } +#ifdef GST_EXT_ENABLE_HEVC +static void +gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf) +{ + unsigned int outsize = 0; + unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data; + int cnt = 0, j = 0; + unsigned char *temp_imgb; + SCMN_IMGB *imgb = NULL; + int stride, w, h, i; + + GST_DEBUG("Begin"); + imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf); + if(imgb == NULL || imgb->a[0] == NULL) + { + return; + } + + stride = GST_ROUND_UP_4 (imgb->w[0]); + h = imgb->h[0]; + w = imgb->w[0]; + /*Y plane copy */ + for (i = 0; i < h; i++) + { + memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w); + } + + temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]); + + stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2); + h = GST_ROUND_UP_2 (imgb->h[0]) / 2; + w = GST_ROUND_UP_2 (imgb->w[0]) / 2; + /* Cb plane copy */ + for (i = 0; i < h; i++) + { + memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w); + } + + temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2); + /* Same stride, height, width as above */ + /* Cr plane copy */ + for (i = 0; i < h; i++) + { + memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w); + } + + outsize = imgb->w[0] * imgb->h[0]* 3 >> 1; + xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size); + + GST_DEBUG("End"); +} +#endif + +#ifdef GST_EXT_XV_ENHANCEMENT +static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink) +{ + GstXvImageFlushBuffer *flush_buffer = NULL; + GstXvImageDisplayingBuffer *display_buffer = NULL; + tbm_bo bo = NULL; + int size = 0; + int i = 0; + int ret = 0; + + if (xvimagesink == NULL) { + GST_ERROR("handle is NULL"); + return FALSE; + } + + if (xvimagesink->last_added_buffer_index == -1) { + GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer"); + return FALSE; + } + + if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) { + GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid", + xvimagesink->drm_fd, xvimagesink->bufmgr); + return FALSE; + } + + flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer)); + if (flush_buffer == NULL) { + GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed"); + return FALSE; + } + + memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer)); + + display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]); + GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]", + xvimagesink->last_added_buffer_index); + + for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) { + if (display_buffer->bo[i]) { + tbm_bo_handle vaddr_src; + tbm_bo_handle vaddr_dst; + + /* get bo size */ + size = tbm_bo_size(display_buffer->bo[i]); + + /* alloc bo */ + bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT); + if (bo == NULL) { + GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size); + goto FLUSH_BUFFER_FAILED; + } + + GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size); + + flush_buffer->gem_name[i] = tbm_bo_export(bo); + flush_buffer->bo[i] = bo; + + /* get virtual address */ + vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) { + GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p", + vaddr_src.ptr, vaddr_dst.ptr); + if (vaddr_src.ptr) { + tbm_bo_unmap(display_buffer->bo[i]); + } + if (vaddr_dst.ptr) { + tbm_bo_unmap(bo); + } + goto FLUSH_BUFFER_FAILED; + } + + /* copy buffer */ + memcpy(vaddr_dst.ptr, vaddr_src.ptr, size); + + tbm_bo_unmap(display_buffer->bo[i]); + tbm_bo_unmap(bo); + + GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i); + + xvimagesink->flush_buffer = flush_buffer; + + ret = TRUE; + } + } + + return ret; + +FLUSH_BUFFER_FAILED: + if (flush_buffer) { + for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) { + if (flush_buffer->bo[i]) { + tbm_bo_unref(flush_buffer->bo[i]); + flush_buffer->bo[i] = NULL; + } + } + free(flush_buffer); + flush_buffer = NULL; + } + + return FALSE; +} +#endif /* GST_EXT_XV_ENHANCEMENT */ + + static GstFlowReturn gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) { GstXvImageSink *xvimagesink; #ifdef GST_EXT_XV_ENHANCEMENT - XV_PUTIMAGE_DATA_PTR img_data = NULL; + XV_DATA_PTR img_data = NULL; SCMN_IMGB *scmn_imgb = NULL; gint format = 0; + gboolean ret = FALSE; + int res = -1; + int (*handler) (Display *, XErrorEvent *) = NULL; + Atom atom_overlay; #endif /* GST_EXT_XV_ENHANCEMENT */ xvimagesink = GST_XVIMAGESINK (vsink); @@ -3126,6 +5308,9 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) put the ximage which is in the PRIVATE pointer */ if (GST_IS_XVIMAGE_BUFFER (buf)) { GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf); +#ifdef GST_EXT_XV_ENHANCEMENT + xvimagesink->xid_updated = FALSE; +#endif /* GST_EXT_XV_ENHANCEMENT */ if (!gst_xvimagesink_xvimage_put (xvimagesink, GST_XVIMAGE_BUFFER_CAST (buf))) goto no_window; @@ -3134,21 +5319,41 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) "slow copy into bufferpool buffer %p", buf); /* Else we have to copy the data into our private image, */ /* if we have one... */ - if (!xvimagesink->xvimage) { - GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage"); +#ifdef GST_EXT_XV_ENHANCEMENT + g_mutex_lock (xvimagesink->flow_lock); + if (xvimagesink->skip_frame_due_to_external_dev) { + GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." ); + xvimagesink->skip_frame_due_to_external_dev = FALSE; + g_mutex_unlock (xvimagesink->flow_lock); + return GST_FLOW_OK; + } + +#endif /* GST_EXT_XV_ENHANCEMENT */ + if (!xvimagesink->xvimage +#ifdef GST_EXT_XV_ENHANCEMENT + && !xvimagesink->is_subpicture_format +#endif + ) { + GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage"); #ifdef GST_EXT_XV_ENHANCEMENT format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf)); switch (format) { case GST_MAKE_FOURCC('S', 'T', '1', '2'): case GST_MAKE_FOURCC('S', 'N', '1', '2'): + case GST_MAKE_FOURCC('S', 'N', '2', '1'): case GST_MAKE_FOURCC('S', '4', '2', '0'): case GST_MAKE_FOURCC('S', 'U', 'Y', '2'): case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'): case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC('I', 'T', 'L', 'V'): + case GST_MAKE_FOURCC('S', 'R', '3', '2'): + case GST_MAKE_FOURCC('S', 'V', '1', '2'): + xvimagesink->is_zero_copy_format = TRUE; scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf); if(scmn_imgb == NULL) { GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." ); + g_mutex_unlock (xvimagesink->flow_lock); return GST_FLOW_OK; } @@ -3158,6 +5363,7 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...", xvimagesink->video_width, xvimagesink->video_height, scmn_imgb->s[0], scmn_imgb->e[0]); + g_mutex_unlock (xvimagesink->flow_lock); return GST_FLOW_OK; } @@ -3167,9 +5373,12 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) xvimagesink->aligned_width, xvimagesink->aligned_height); break; default: + xvimagesink->is_zero_copy_format = FALSE; GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps"); break; } + + GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format); #endif /* GST_EXT_XV_ENHANCEMENT */ xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink, @@ -3179,7 +5388,14 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) /* The create method should have posted an informative error */ goto no_image; +#ifdef GST_EXT_XV_ENHANCEMENT + if ((xvimagesink->is_zero_copy_format == FALSE && + xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) || + (xvimagesink->is_zero_copy_format && + xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) { +#else /* GST_EXT_XV_ENHANCEMENT */ if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) { +#endif /* GST_EXT_XV_ENHANCEMENT */ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", xvimagesink->xvimage->width, xvimagesink->xvimage->height), @@ -3192,61 +5408,232 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) } #ifdef GST_EXT_XV_ENHANCEMENT - switch (xvimagesink->xvimage->im_format) { + if (xvimagesink->is_zero_copy_format) { /* Cases for specified formats of Samsung extension */ - case GST_MAKE_FOURCC('S', 'T', '1', '2'): - case GST_MAKE_FOURCC('S', 'N', '1', '2'): - case GST_MAKE_FOURCC('S', '4', '2', '0'): - case GST_MAKE_FOURCC('S', 'U', 'Y', '2'): - case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'): - case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'): - case GST_MAKE_FOURCC('I', 'T', 'L', 'V'): - { - GST_DEBUG("Samsung extension display format activated. fourcc:%d,display mode:%d,Rotate angle:%d", - xvimagesink->xvimage->im_format, xvimagesink->display_mode, xvimagesink->rotate_angle); + GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d", + xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8, + xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24, + xvimagesink->display_mode, xvimagesink->rotate_angle); if (xvimagesink->xvimage->xvimage->data) { - img_data = (XV_PUTIMAGE_DATA_PTR) xvimagesink->xvimage->xvimage->data; - XV_PUTIMAGE_INIT_DATA(img_data); + int i = 0; + img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data; + memset(img_data, 0x0, sizeof(XV_DATA)); + XV_INIT_DATA(img_data); scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf); if (scmn_imgb == NULL) { GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." ); + g_mutex_unlock (xvimagesink->flow_lock); return GST_FLOW_OK; } - img_data->YPhyAddr = (unsigned int)scmn_imgb->p[0]; - img_data->CbPhyAddr = (unsigned int)scmn_imgb->p[1]; - img_data->CrPhyAddr = (unsigned int)scmn_imgb->p[2]; + /* Keep the vaddr of current image for copying last image */ + if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) { + for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) { + xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i]; + } + GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]", + xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]); + } + + if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) { + img_data->YBuf = (unsigned int)scmn_imgb->p[0]; + img_data->CbBuf = (unsigned int)scmn_imgb->p[1]; + img_data->CrBuf = (unsigned int)scmn_imgb->p[2]; + img_data->BufType = XV_BUF_TYPE_LEGACY; + + GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]", + img_data->YBuf, img_data->CbBuf, img_data->CrBuf ); + } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD || + scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) { + gboolean do_set_secure = FALSE; + + /* open drm to use gem */ + if (xvimagesink->drm_fd < 0) { + drm_init(xvimagesink); + } + + if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) { + /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */ + img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0]; + img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1]; + img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2]; + img_data->BufType = XV_BUF_TYPE_DMABUF; + GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]); + } else { + /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */ + img_data->bo[0] = scmn_imgb->bo[0]; + img_data->bo[1] = scmn_imgb->bo[1]; + img_data->bo[2] = scmn_imgb->bo[2]; + GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]); + } + + /* check secure contents path */ + if (scmn_imgb->tz_enable) { + if (xvimagesink->secure_path != SECURE_PATH_ON) { + xvimagesink->secure_path = SECURE_PATH_ON; + do_set_secure = TRUE; + } + } else { + if (xvimagesink->secure_path != SECURE_PATH_OFF) { + xvimagesink->secure_path = SECURE_PATH_OFF; + do_set_secure = TRUE; + } + } + static gboolean is_exist = FALSE; + gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + + if (do_set_secure && is_exist) { + Atom atom_secure = None; + g_mutex_lock (xvimagesink->x_lock); + atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False); + if (atom_secure != None) { + if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) { + GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure); + } else { + GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path); + } + XSync (xvimagesink->xcontext->disp, FALSE); + } else { + GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed"); + } + g_mutex_unlock (xvimagesink->x_lock); + } + + is_exist = FALSE; + attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + - GST_LOG_OBJECT(xvimagesink, "Ypaddr[%p],CbPaddr[%p],CrPaddr[%p]", - img_data->YPhyAddr, img_data->CbPhyAddr, img_data->CrPhyAddr ); + if (xvimagesink->drm_level && is_exist) { + Atom atom_drm = None; + g_mutex_lock (xvimagesink->x_lock); + atom_drm = XInternAtom( xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False); + if (atom_drm != None) { + GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1"); + if (XvSetPortAttribute(xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + atom_drm, xvimagesink->drm_level ) != Success) { + GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" ); + } + XSync (xvimagesink->xcontext->disp, FALSE); + g_mutex_unlock (xvimagesink->x_lock); + xvimagesink->drm_level = DRM_LEVEL_0; + } + } - img_data->RotAngle = xvimagesink->rotate_angle; - img_data->VideoMode = xvimagesink->display_mode; + /* set current buffer */ + xvimagesink->xvimage->current_buffer = buf; + } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) { + /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */ + GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case"); + if (gst_xvimagesink_make_flush_buffer(xvimagesink)) { + img_data->bo[0] = xvimagesink->flush_buffer->bo[0]; + img_data->bo[1] = xvimagesink->flush_buffer->bo[1]; + img_data->bo[2] = xvimagesink->flush_buffer->bo[2]; + } else { + g_mutex_unlock(xvimagesink->flow_lock); + return GST_FLOW_OK; + } + } else { + GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...", + scmn_imgb->buf_share_method); + g_mutex_unlock (xvimagesink->flow_lock); + return GST_FLOW_OK; + } } else { GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." ); + g_mutex_unlock (xvimagesink->flow_lock); return GST_FLOW_OK; } - break; + } else if (xvimagesink->is_subpicture_format) { + GC gc; + xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf); + if(!xvimagesink->pixmap_for_subpicture) { + GST_ERROR("no pixmap"); + g_mutex_unlock (xvimagesink->flow_lock); + return GST_FLOW_OK; } - default: + if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) { + GST_ERROR("pixmap's size and current resolution are different"); + g_mutex_unlock (xvimagesink->flow_lock); + return GST_FLOW_OK; + } + gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0); + + GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture, + xvimagesink->xcontext->xv_port_id, gc); + + /* set error handler */ + error_caught = FALSE; + handler = XSetErrorHandler(gst_xvimagesink_handle_xerror); + + if(!xvimagesink->set_overlay_for_subpicture_just_once) { - GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format); - memcpy (xvimagesink->xvimage->xvimage->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); - break; + GST_LOG("setting attribute overlay"); + atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE); + XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1); + XSync (xvimagesink->xcontext->disp, FALSE); + xvimagesink->set_overlay_for_subpicture_just_once = TRUE; + } + res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, + xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height, + 0, 0, xvimagesink->external_width, xvimagesink->external_height); + XSync (xvimagesink->xcontext->disp, FALSE); + + GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)), + GST_TIME_ARGS(GST_BUFFER_DURATION(buf)), + GST_BUFFER_SIZE(buf)); + if(gc) { + GST_DEBUG("FreeGC"); + XFreeGC (xvimagesink->xcontext->disp, gc); } + if (error_caught) + GST_WARNING_OBJECT(xvimagesink, "XvGetStill error"); + else + GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height); + + /* Reset error handler */ + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } + } else { + GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format); + +#ifdef GST_EXT_ENABLE_HEVC + if(xvimagesink->need_combine_data == 1) + { + gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf); + } + else +#endif + { + memcpy (xvimagesink->xvimage->xvimage->data, + GST_BUFFER_DATA (buf), + MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); + } + } + + g_mutex_unlock (xvimagesink->flow_lock); + ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage); + if (!ret && !xvimagesink->is_subpicture_format) { + goto no_window; } #else /* GST_EXT_XV_ENHANCEMENT */ memcpy (xvimagesink->xvimage->xvimage->data, GST_BUFFER_DATA (buf), MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); -#endif /* GST_EXT_XV_ENHANCEMENT */ if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage)) goto no_window; +#endif /* GST_EXT_XV_ENHANCEMENT */ } return GST_FLOW_OK; @@ -3256,6 +5643,9 @@ no_image: { /* No image available. That's very bad ! */ GST_WARNING_OBJECT (xvimagesink, "could not create image"); +#ifdef GST_EXT_XV_ENHANCEMENT + g_mutex_unlock (xvimagesink->flow_lock); +#endif return GST_FLOW_ERROR; } no_window: @@ -3270,6 +5660,11 @@ static gboolean gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event) { GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink); + if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) + { + if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK)) + GST_WARNING("vconf set fail"); + } switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ @@ -3280,14 +5675,76 @@ gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event) gst_tag_list_get_string (l, GST_TAG_TITLE, &title); if (title) { +#ifdef GST_EXT_XV_ENHANCEMENT + if (!xvimagesink->get_pixmap_cb) { +#endif GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title); gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow, title); g_free (title); +#ifdef GST_EXT_XV_ENHANCEMENT + } +#endif + } + break; + } +#ifdef GST_EXT_XV_ENHANCEMENT + case GST_EVENT_FLUSH_START: + GST_DEBUG_OBJECT (xvimagesink, "flush start"); + break; + case GST_EVENT_FLUSH_STOP: + GST_DEBUG_OBJECT (xvimagesink, "flush stop"); + xvimagesink->is_during_seek = TRUE; + break; + case GST_EVENT_CUSTOM_DOWNSTREAM: + { + const GstStructure *st = NULL; + st = gst_event_get_structure (event); + if(!st) { + GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event"); + } else { + if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) { + GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready"); + xvimagesink->drm_level = DRM_LEVEL_1; + if (xvimagesink->drm_level && xvimagesink->xcontext) { + static gboolean is_exist = FALSE; + gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL"); + is_exist = check_supportable_port_attr(xvimagesink, attr_name); + g_free(attr_name); + + if(is_exist) + { + Atom atom_drm = None; + g_mutex_lock (xvimagesink->x_lock); + atom_drm = XInternAtom( xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False); + if (atom_drm != None) { + GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1"); + if (XvSetPortAttribute(xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + atom_drm, xvimagesink->drm_level ) != Success) { + GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" ); + } + XSync (xvimagesink->xcontext->disp, FALSE); + xvimagesink->drm_level = DRM_LEVEL_0; + } + g_mutex_unlock (xvimagesink->x_lock); + } + } + } } break; } + case GST_EVENT_EOS: + xvimagesink->eos_received = TRUE; + GST_DEBUG_OBJECT(xvimagesink, "got eos"); + break; + case GST_EVENT_NEWSEGMENT: + xvimagesink->eos_received = FALSE; + GST_DEBUG_OBJECT(xvimagesink, "got newsegment event"); + break; +#endif default: break; } @@ -3509,6 +5966,12 @@ reuse_last_caps: } if (!xvimage) { +#ifdef GST_EXT_XV_ENHANCEMENT + /* init aligned size */ + xvimagesink->aligned_width = 0; + xvimagesink->aligned_height = 0; +#endif /* GST_EXT_XV_ENHANCEMENT */ + /* We found no suitable image in the pool. Creating... */ GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage"); xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection); @@ -3652,19 +6115,137 @@ gst_xvimagesink_navigation_init (GstNavigationInterface * iface) iface->send_event = gst_xvimagesink_navigation_send_event; } +#ifdef GST_EXT_XV_ENHANCEMENT +static void +gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id) +{ + XID pixmap_id = id; + int i = 0; + GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); + GstXPixmap *xpixmap = NULL; + int (*handler) (Display *, XErrorEvent *); + + g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); + + if (xvimagesink->subpicture) + return; + + /* If the element has not initialized the X11 context try to do so */ + if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) { + /* we have thrown a GST_ELEMENT_ERROR now */ + return; + } + + gst_xvimagesink_update_colorbalance (xvimagesink); + + GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id ); + + /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */ + if (pixmap_id == 0) { + xvimagesink->current_pixmap_idx = -2; + return; + } + + g_mutex_lock (xvimagesink->x_lock); + + for (i = 0; i < MAX_PIXMAP_NUM; i++) { + if (!xvimagesink->xpixmap[i]) { + Window root_window; + int cur_win_x = 0; + int cur_win_y = 0; + unsigned int cur_win_width = 0; + unsigned int cur_win_height = 0; + unsigned int cur_win_border_width = 0; + unsigned int cur_win_depth = 0; + + GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id ); + + xpixmap = g_new0 (GstXPixmap, 1); + if (xpixmap) { + xpixmap->pixmap = pixmap_id; + + /* Get root window and size of current window */ + XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window, + &cur_win_x, &cur_win_y, /* relative x, y */ + &cur_win_width, &cur_win_height, + &cur_win_border_width, &cur_win_depth); + if (!cur_win_width || !cur_win_height) { + GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height ); + g_mutex_unlock (xvimagesink->x_lock); + return; + } + xpixmap->width = cur_win_width; + xpixmap->height = cur_win_height; + + if (!xvimagesink->render_rect.w) + xvimagesink->render_rect.w = cur_win_width; + if (!xvimagesink->render_rect.h) + xvimagesink->render_rect.h = cur_win_height; + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); + + /* Create a GC */ + xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL); + + XSync(xvimagesink->xcontext->disp, FALSE); + if (error_caught) { + GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap); + } + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } + + xvimagesink->xpixmap[i] = xpixmap; + xvimagesink->current_pixmap_idx = i; + } else { + GST_ERROR("failed to create xpixmap errno: %d", errno); + } + + g_mutex_unlock (xvimagesink->x_lock); + return; + + } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) { + GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id ); + xvimagesink->current_pixmap_idx = i; + + g_mutex_unlock (xvimagesink->x_lock); + return; + + } else { + continue; + } + } + + GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id ); + xvimagesink->current_pixmap_idx = -1; + + g_mutex_unlock (xvimagesink->x_lock); + return; +} +#endif /* GST_EXT_XV_ENHANCEMENT */ + static void gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id) { XID xwindow_id = id; GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); GstXWindow *xwindow = NULL; +#ifdef GST_EXT_XV_ENHANCEMENT + GstState current_state = GST_STATE_NULL; + int (*handler) (Display *, XErrorEvent *); +#endif /* GST_EXT_XV_ENHANCEMENT */ g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); g_mutex_lock (xvimagesink->flow_lock); #ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT( xvimagesink, "ENTER, id : %d", xwindow_id ); + gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0); + GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d", + xwindow_id, current_state); #endif /* GST_EXT_XV_ENHANCEMENT */ /* If we already use that window return */ @@ -3722,7 +6303,8 @@ gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id) /* Set the event we want to receive and create a GC */ g_mutex_lock (xvimagesink->x_lock); - XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr); + if(!xvimagesink->is_pixmap) + XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr); xwindow->width = attr.width; xwindow->height = attr.height; @@ -3733,20 +6315,59 @@ gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id) xvimagesink->render_rect.h = attr.height; } if (xvimagesink->handle_events) { +#ifdef GST_EXT_XV_ENHANCEMENT + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask); + XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask | PropertyChangeMask); +#else XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask); - } +#endif + } +#ifdef GST_EXT_XV_ENHANCEMENT + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); +#endif xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, xwindow->win, 0, NULL); +#ifdef GST_EXT_XV_ENHANCEMENT + XSync(xvimagesink->xcontext->disp, FALSE); + if (error_caught) { + GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win); + } + if (handler) { + error_caught = FALSE; + XSetErrorHandler (handler); + } +#endif g_mutex_unlock (xvimagesink->x_lock); } if (xwindow) xvimagesink->xwindow = xwindow; +#ifdef GST_EXT_XV_ENHANCEMENT + xvimagesink->xid_updated = TRUE; +#endif /* GST_EXT_XV_ENHANCEMENT */ + g_mutex_unlock (xvimagesink->flow_lock); + +#ifdef GST_EXT_XV_ENHANCEMENT + if (current_state == GST_STATE_PAUSED) { + GstBuffer *last_buffer = NULL; + g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL); + GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer); + if (last_buffer) { + gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer); + gst_buffer_unref(last_buffer); + last_buffer = NULL; + } + } +#endif /* GST_EXT_XV_ENHANCEMENT */ } static void @@ -3756,11 +6377,9 @@ gst_xvimagesink_expose (GstXOverlay * overlay) gst_xvimagesink_xwindow_update_geometry (xvimagesink); #ifdef GST_EXT_XV_ENHANCEMENT - GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it"); - gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); -#else /* GST_EXT_XV_ENHANCEMENT */ - gst_xvimagesink_xvimage_put (xvimagesink, NULL); + GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it"); #endif /* GST_EXT_XV_ENHANCEMENT */ + gst_xvimagesink_xvimage_put (xvimagesink, NULL); } static void @@ -3782,12 +6401,26 @@ gst_xvimagesink_set_event_handling (GstXOverlay * overlay, if (handle_events) { if (xvimagesink->xwindow->internal) { +#ifdef GST_EXT_XV_ENHANCEMENT + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask); +#endif XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, +#ifdef GST_EXT_XV_ENHANCEMENT + ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask | +#else /* GST_EXT_XV_ENHANCEMENT */ ExposureMask | StructureNotifyMask | PointerMotionMask | +#endif /* GST_EXT_XV_ENHANCEMENT */ KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); } else { +#ifdef GST_EXT_XV_ENHANCEMENT + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask); +#endif XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, +#ifdef GST_EXT_XV_ENHANCEMENT + ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask | +#else /* GST_EXT_XV_ENHANCEMENT */ ExposureMask | StructureNotifyMask | PointerMotionMask | +#endif /* GST_EXT_XV_ENHANCEMENT */ KeyPressMask | KeyReleaseMask); } } else { @@ -4162,25 +6795,52 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, case PROP_DISPLAY_MODE: { int set_mode = g_value_get_enum (value); + g_mutex_lock(xvimagesink->flow_lock); + xvimagesink->display_mode = set_mode; + if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) { + if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) { + if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) { + set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode); + } else { + GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode); + } + } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){ + if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) { + set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode); + } else { + GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode); + } + } else { + GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode); + } + } + g_mutex_unlock(xvimagesink->flow_lock); + } + break; + case PROP_CSC_RANGE: + { + int set_range = g_value_get_enum (value); g_mutex_lock(xvimagesink->flow_lock); g_mutex_lock(xvimagesink->x_lock); - if (xvimagesink->display_mode != set_mode) { - if (xvimagesink->xcontext) { - /* set display mode */ - if (set_display_mode(xvimagesink->xcontext, set_mode)) { - xvimagesink->display_mode = set_mode; + if (xvimagesink->csc_range != set_range) { + if (xvimagesink->xcontext && !xvimagesink->subpicture) { + /* set color space range */ + if (set_csc_range(xvimagesink->xcontext, set_range)) { + xvimagesink->csc_range = set_range; } else { - GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode); + GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range); } } else { /* "xcontext" is not created yet. It will be applied when xcontext is created. */ - GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later."); - xvimagesink->display_mode = set_mode; + GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later."); + xvimagesink->csc_range = set_range; } + } else if (xvimagesink->subpicture) { + GST_WARNING("skip to set csc range, because it is subpicture format."); } else { - GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode); + GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range); } g_mutex_unlock(xvimagesink->x_lock); @@ -4190,44 +6850,86 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, case PROP_DISPLAY_GEOMETRY_METHOD: xvimagesink->display_geometry_method = g_value_get_enum (value); GST_LOG("Overlay geometry changed. update it"); - gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); + if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) { + gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); + } + break; + case PROP_FLIP: + xvimagesink->flip = g_value_get_enum(value); break; case PROP_ROTATE_ANGLE: xvimagesink->rotate_angle = g_value_get_enum (value); - xvimagesink->rotate_changed = TRUE; + if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) { + gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); + } break; case PROP_VISIBLE: g_mutex_lock( xvimagesink->flow_lock ); g_mutex_lock( xvimagesink->x_lock ); + GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value)); + if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) { - Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp, - "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False ); - if (atom_stream != None) { - if (XvSetPortAttribute(xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - atom_stream, 0 ) != Success) { - GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" ); + if (xvimagesink->xcontext) { +#if 0 + Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp, + "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False ); + if (atom_stream != None) { + GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF"); + if (XvSetPortAttribute(xvimagesink->xcontext->disp, + xvimagesink->xcontext->xv_port_id, + atom_stream, 0 ) != Success) { + GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" ); + } + } +#endif + xvimagesink->visible = g_value_get_boolean (value); + if ( xvimagesink->get_pixmap_cb ) { + if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) { + XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap); + } + } else { + if(xvimagesink->xwindow->win) + XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win); } - XSync( xvimagesink->xcontext->disp, FALSE ); + } else { + GST_WARNING_OBJECT( xvimagesink, "xcontext is null"); + xvimagesink->visible = g_value_get_boolean (value); } } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) { + xvimagesink->visible = g_value_get_boolean (value); g_mutex_unlock( xvimagesink->x_lock ); g_mutex_unlock( xvimagesink->flow_lock ); - GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." ); gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); g_mutex_lock( xvimagesink->flow_lock ); g_mutex_lock( xvimagesink->x_lock ); } - xvimagesink->visible = g_value_get_boolean (value); + GST_INFO("set visible(%d) done", xvimagesink->visible); g_mutex_unlock( xvimagesink->x_lock ); g_mutex_unlock( xvimagesink->flow_lock ); break; case PROP_ZOOM: - xvimagesink->zoom = g_value_get_int (value); + xvimagesink->zoom = g_value_get_float (value); + break; + case PROP_ZOOM_POS_X: + xvimagesink->zoom_pos_x = g_value_get_int (value); + break; + case PROP_ZOOM_POS_Y: + xvimagesink->zoom_pos_y = g_value_get_int (value); + if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) { + gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); + } + break; + case PROP_ORIENTATION: + xvimagesink->orientation = g_value_get_enum (value); + GST_INFO("Orientation(%d) is changed", xvimagesink->orientation); + break; + case PROP_DST_ROI_MODE: + xvimagesink->dst_roi_mode = g_value_get_enum (value); + GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode); break; case PROP_DST_ROI_X: xvimagesink->dst_roi.x = g_value_get_int (value); @@ -4241,18 +6943,134 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, case PROP_DST_ROI_H: xvimagesink->dst_roi.h = g_value_get_int (value); break; + case PROP_SRC_CROP_X: + xvimagesink->src_crop.x = g_value_get_int (value); + break; + case PROP_SRC_CROP_Y: + xvimagesink->src_crop.y = g_value_get_int (value); + break; + case PROP_SRC_CROP_W: + xvimagesink->src_crop.w = g_value_get_int (value); + break; + case PROP_SRC_CROP_H: + xvimagesink->src_crop.h = g_value_get_int (value); + break; case PROP_STOP_VIDEO: xvimagesink->stop_video = g_value_get_int (value); g_mutex_lock( xvimagesink->flow_lock ); if( xvimagesink->stop_video ) { - GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" ); - gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); + if ( xvimagesink->get_pixmap_cb ) { + if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) { + g_mutex_lock (xvimagesink->x_lock); + GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" ); + XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap); + g_mutex_unlock (xvimagesink->x_lock); + } + } else { + GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" ); + gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); + } } g_mutex_unlock( xvimagesink->flow_lock ); break; + case PROP_PIXMAP_CB: + { + void *cb_func; + cb_func = g_value_get_pointer(value); + if (cb_func) { + if (xvimagesink->get_pixmap_cb) { + int i = 0; + if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) { + g_mutex_lock (xvimagesink->x_lock); + GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" ); + XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap); + g_mutex_unlock (xvimagesink->x_lock); + } + for (i = 0; i < MAX_PIXMAP_NUM; i++) { + if (xvimagesink->xpixmap[i]) { + gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]); + xvimagesink->xpixmap[i] = NULL; + } + } + } + xvimagesink->get_pixmap_cb = cb_func; + GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb); + } + break; + } + case PROP_PIXMAP_CB_USER_DATA: + { + void *user_data; + user_data = g_value_get_pointer(value); + if (user_data) { + xvimagesink->get_pixmap_cb_user_data = user_data; + GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data); + } + break; + } + case PROP_SUBPICTURE: + xvimagesink->subpicture = g_value_get_boolean (value); + break; + case PROP_EXTERNAL_WIDTH: + { + xvimagesink->external_width = g_value_get_int (value); + GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width); + break; + } + case PROP_EXTERNAL_HEIGHT: + { + xvimagesink->external_height = g_value_get_int (value); + GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height); + break; + } + case PROP_ENABLE_FLUSH_BUFFER: + xvimagesink->enable_flush_buffer = g_value_get_boolean(value); + break; + case PROP_PIXMAP: + xvimagesink->is_pixmap = g_value_get_boolean(value); + break; + case PROP_HIDED_WINDOW: + { + xvimagesink->is_hided_subpicture = g_value_get_boolean(value); + GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture); + break; + } + case PROP_QUICKPANEL_ON: + { + xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value); + GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture); + break; + } + case PROP_MULTIWINDOW_ACTIVE: + { + xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value); + GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture); + break; + } + case PROP_KEEP_EXTERNAL_FULLSCREEN_POST: + { + xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value); + GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post); + if(xvimagesink->keep_external_fullscreen_post) { + Atom atom_keep_ext; + atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False); + if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success) + { + GST_WARNING("set atom_keep_ext fail"); + } + } + break; + } + case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV: + { + xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value); + GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev); + break; + } + #endif /* GST_EXT_XV_ENHANCEMENT */ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -4346,9 +7164,15 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, case PROP_DISPLAY_MODE: g_value_set_enum (value, xvimagesink->display_mode); break; + case PROP_CSC_RANGE: + g_value_set_enum (value, xvimagesink->csc_range); + break; case PROP_DISPLAY_GEOMETRY_METHOD: g_value_set_enum (value, xvimagesink->display_geometry_method); break; + case PROP_FLIP: + g_value_set_enum(value, xvimagesink->flip); + break; case PROP_ROTATE_ANGLE: g_value_set_enum (value, xvimagesink->rotate_angle); break; @@ -4356,7 +7180,19 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, g_value_set_boolean (value, xvimagesink->visible); break; case PROP_ZOOM: - g_value_set_int (value, xvimagesink->zoom); + g_value_set_float (value, xvimagesink->zoom); + break; + case PROP_ZOOM_POS_X: + g_value_set_int (value, xvimagesink->zoom_pos_x); + break; + case PROP_ZOOM_POS_Y: + g_value_set_int (value, xvimagesink->zoom_pos_y); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, xvimagesink->orientation); + break; + case PROP_DST_ROI_MODE: + g_value_set_enum (value, xvimagesink->dst_roi_mode); break; case PROP_DST_ROI_X: g_value_set_int (value, xvimagesink->dst_roi.x); @@ -4370,9 +7206,57 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, case PROP_DST_ROI_H: g_value_set_int (value, xvimagesink->dst_roi.h); break; + case PROP_SRC_CROP_X: + g_value_set_int (value, xvimagesink->src_crop.x); + break; + case PROP_SRC_CROP_Y: + g_value_set_int (value, xvimagesink->src_crop.y); + break; + case PROP_SRC_CROP_W: + g_value_set_int (value, xvimagesink->src_crop.w); + break; + case PROP_SRC_CROP_H: + g_value_set_int (value, xvimagesink->src_crop.h); + break; case PROP_STOP_VIDEO: g_value_set_int (value, xvimagesink->stop_video); break; + case PROP_PIXMAP_CB: + g_value_set_pointer (value, xvimagesink->get_pixmap_cb); + break; + case PROP_PIXMAP_CB_USER_DATA: + g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data); + break; + case PROP_SUBPICTURE: + g_value_set_boolean (value, xvimagesink->subpicture); + break; + case PROP_EXTERNAL_WIDTH: + g_value_set_int (value, xvimagesink->external_width); + break; + case PROP_EXTERNAL_HEIGHT: + g_value_set_int (value, xvimagesink->external_height); + break; + case PROP_ENABLE_FLUSH_BUFFER: + g_value_set_boolean(value, xvimagesink->enable_flush_buffer); + break; + case PROP_PIXMAP: + g_value_set_boolean(value, xvimagesink->is_pixmap); + break; + case PROP_HIDED_WINDOW: + g_value_set_boolean(value, xvimagesink->is_hided_subpicture); + break; + case PROP_QUICKPANEL_ON: + g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture); + break; + case PROP_MULTIWINDOW_ACTIVE: + g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture); + break; + case PROP_KEEP_EXTERNAL_FULLSCREEN_POST: + g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post); + break; + case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV: + g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev); + break; #endif /* GST_EXT_XV_ENHANCEMENT */ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -4418,7 +7302,31 @@ gst_xvimagesink_reset (GstXvImageSink * xvimagesink) gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); xvimagesink->xwindow = NULL; } +#ifdef GST_EXT_XV_ENHANCEMENT + if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) { + GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture); + XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture); + xvimagesink->pixmap_for_subpicture = 0; + } + if (xvimagesink->get_pixmap_cb) { + int i = 0; + if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) { + g_mutex_lock (xvimagesink->x_lock); + GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" ); + XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap); + g_mutex_unlock (xvimagesink->x_lock); + } + for (i = 0; i < MAX_PIXMAP_NUM; i++) { + if (xvimagesink->xpixmap[i]) { + gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]); + xvimagesink->xpixmap[i] = NULL; + } + } + xvimagesink->get_pixmap_cb = NULL; + xvimagesink->get_pixmap_cb_user_data = NULL; + } +#endif /* GST_EXT_XV_ENHANCEMENT */ xvimagesink->render_rect.x = xvimagesink->render_rect.y = xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0; xvimagesink->have_render_rect = FALSE; @@ -4459,6 +7367,12 @@ gst_xvimagesink_finalize (GObject * object) g_mutex_free (xvimagesink->pool_lock); xvimagesink->pool_lock = NULL; } +#ifdef GST_EXT_XV_ENHANCEMENT + if (xvimagesink->display_buffer_lock) { + g_mutex_free (xvimagesink->display_buffer_lock); + xvimagesink->display_buffer_lock = NULL; + } +#endif /* GST_EXT_XV_ENHANCEMENT */ g_free (xvimagesink->media_title); @@ -4469,6 +7383,11 @@ static void gst_xvimagesink_init (GstXvImageSink * xvimagesink, GstXvImageSinkClass * xvimagesinkclass) { +#ifdef GST_EXT_XV_ENHANCEMENT + int i; + int j; +#endif /* GST_EXT_XV_ENHANCEMENT */ + xvimagesink->display_name = NULL; xvimagesink->adaptor_no = 0; xvimagesink->xcontext = NULL; @@ -4508,17 +7427,27 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink, xvimagesink->draw_borders = TRUE; #ifdef GST_EXT_XV_ENHANCEMENT - xvimagesink->display_mode = DISPLAY_MODE_DEFAULT; - xvimagesink->rotate_changed = TRUE; + xvimagesink->xid_updated = FALSE; + xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE; + xvimagesink->csc_range = CSC_RANGE_NARROW; xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD; + xvimagesink->flip = DEF_DISPLAY_FLIP; xvimagesink->rotate_angle = DEGREE_270; xvimagesink->visible = TRUE; - xvimagesink->zoom = 1; + xvimagesink->zoom = 1.0; + xvimagesink->zoom_pos_x = -1; + xvimagesink->zoom_pos_y = -1; xvimagesink->rotation = -1; + xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD; + xvimagesink->orientation = DEGREE_0; xvimagesink->dst_roi.x = 0; xvimagesink->dst_roi.y = 0; xvimagesink->dst_roi.w = 0; xvimagesink->dst_roi.h = 0; + xvimagesink->src_crop.x = 0; + xvimagesink->src_crop.y = 0; + xvimagesink->src_crop.w = 0; + xvimagesink->src_crop.h = 0; xvimagesink->xim_transparenter = NULL; xvimagesink->scr_w = 0; xvimagesink->scr_h = 0; @@ -4526,6 +7455,50 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink, xvimagesink->aligned_height = 0; xvimagesink->stop_video = FALSE; xvimagesink->is_hided = FALSE; + xvimagesink->is_quick_panel_on = FALSE; + xvimagesink->is_multi_window = FALSE; + xvimagesink->drm_fd = -1; + xvimagesink->current_pixmap_idx = -1; + xvimagesink->get_pixmap_cb = NULL; + xvimagesink->get_pixmap_cb_user_data = NULL; + + for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) { + xvimagesink->displaying_buffers[i].buffer = NULL; + for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) { + xvimagesink->displaying_buffers[i].gem_name[j] = 0; + xvimagesink->displaying_buffers[i].gem_handle[j] = 0; + xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0; + xvimagesink->displaying_buffers[i].ref_count = 0; + } + } + + xvimagesink->display_buffer_lock = g_mutex_new (); + + xvimagesink->displayed_buffer_count = 0; + xvimagesink->displaying_buffer_count = 0; + xvimagesink->is_zero_copy_format = FALSE; + xvimagesink->secure_path = SECURE_PATH_INIT; + xvimagesink->drm_level = DRM_LEVEL_0; + xvimagesink->last_added_buffer_index = -1; + xvimagesink->bufmgr = NULL; + xvimagesink->flush_buffer = NULL; + xvimagesink->enable_flush_buffer = TRUE; + xvimagesink->pixmap_for_subpicture = 0; + xvimagesink->is_subpicture_format = FALSE; + xvimagesink->set_overlay_for_subpicture_just_once = FALSE; + xvimagesink->subpicture = FALSE; + xvimagesink->external_width = 0; + xvimagesink->external_height = 0; + xvimagesink->skip_frame_due_to_external_dev = FALSE; + xvimagesink->is_hided_subpicture = FALSE; + xvimagesink->is_quick_panel_on_subpicture = FALSE; + xvimagesink->is_multi_window_subpicture = FALSE; + xvimagesink->keep_external_fullscreen_post = FALSE; + xvimagesink->keep_external_fullscreen_prev = FALSE; + if(!XInitThreads()) + GST_WARNING("FAIL to call XInitThreads()"); + if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL)) + GST_WARNING("vconf set fail"); #endif /* GST_EXT_XV_ENHANCEMENT */ } @@ -4600,6 +7573,14 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) g_param_spec_string ("device-name", "Adaptor name", "The name of the video adaptor", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH, + g_param_spec_int ("external-width", "external width", + "width of external display", 0, G_MAXINT, + 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT, + g_param_spec_int ("external-height", "external height", + "height of external display", 0, G_MAXINT, + 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstXvImageSink:handle-expose * @@ -4694,7 +7675,18 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE, g_param_spec_enum("display-mode", "Display Mode", "Display device setting", - GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT, + GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:csc-range + * + * select color space range + */ + g_object_class_install_property(gobject_class, PROP_CSC_RANGE, + g_param_spec_enum("csc-range", "Color Space Range", + "Color space range setting", + GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** @@ -4709,6 +7701,17 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** + * GstXvImageSink:display-flip + * + * Display flip setting + */ + g_object_class_install_property(gobject_class, PROP_FLIP, + g_param_spec_enum("flip", "Display flip", + "Flip for display", + GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** * GstXvImageSink:rotate * * Draw rotation angle setting @@ -4732,14 +7735,56 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) /** * GstXvImageSink:zoom * - * Scale small area of screen to 2X, 3X, ... , 9X + * Scale small area of screen to 1X~ 9X */ g_object_class_install_property (gobject_class, PROP_ZOOM, - g_param_spec_int ("zoom", "Zoom", - "Zooms screen as nX", 1, 9, 1, + g_param_spec_float ("zoom", "Zoom", + "Zooms screen as nX", 1.0, 9.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:zoom-pos-x + * + * Standard x-position of zoom + */ + g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X, + g_param_spec_int ("zoom-pos-x", "Zoom Position X", + "Standard x-position of zoom", -1, 3840, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** + * GstXvImageSink:zoom-pos-y + * + * Standard y-position of zoom + */ + g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y, + g_param_spec_int ("zoom-pos-y", "Zoom Position Y", + "Standard y-position of zoom", -1, 3840, -1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:dst-roi-mode + * + * Display geometrical method of ROI setting + */ + g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE, + g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI", + "Geometrical method of ROI for display", + GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:orientation + * + * Orientation information which will be used for ROI/ZOOM + */ + g_object_class_install_property(gobject_class, PROP_ORIENTATION, + g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM", + "Orientation information for display", + GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** * GstXvImageSink:dst-roi-x * * X value of Destination ROI @@ -4788,6 +7833,220 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) g_param_spec_int ("stop-video", "Stop-Video", "Stop video for releasing video source buffer", 0, 1, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PIXMAP_CB, + g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback", + "pointer of callback function for getting pixmap id", G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA, + g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata", + "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_SUBPICTURE, + g_param_spec_boolean ("subpicture", "Subpicture", + "identifier of player for supporting subpicture", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:src-crop-x + * + * X value of video source crop + */ + g_object_class_install_property (gobject_class, PROP_SRC_CROP_X, + g_param_spec_int ("src-crop-x", "Source Crop X", + "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:src-crop-y + * + * Y value of video source crop + */ + g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y, + g_param_spec_int ("src-crop-y", "Source Crop X", + "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:src-crop-w + * + * Width value of video source crop + */ + g_object_class_install_property (gobject_class, PROP_SRC_CROP_W, + g_param_spec_int ("src-crop-w", "Source Crop Width", + "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:src-crop-h + * + * Height value of video source crop + */ + g_object_class_install_property (gobject_class, PROP_SRC_CROP_H, + g_param_spec_int ("src-crop-h", "Source Crop Height", + "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:enable-flush-buffer + * + * Enable flush buffer mechanism when state change(PAUSED_TO_READY) + */ + g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER, + g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism", + "Enable flush buffer mechanism when state change(PAUSED_TO_READY)", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:is-pixmap + * + * Check using pixmap id for blocking X api + */ + g_object_class_install_property (gobject_class, PROP_PIXMAP, + g_param_spec_boolean("is-pixmap", "Check if use pixmap", + "Check using pixmap id for blocking X api", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:hided-window + * + * check window status for hiding subtitle + */ + g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW, + g_param_spec_boolean("hided-window", "Hided window", + "check window status for hiding subtitle", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:quick-panel-on + * + * check quick-panel status for hiding subtitle + */ + g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON, + g_param_spec_boolean("quick-panel-on", "Quick panel On", + "check quick-panel status for hiding subtitle", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:multiwindow-activated + * + * check multiwindow-activated status for hiding subtitle + */ + g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE, + g_param_spec_boolean("multiwindow-active", "Multiwindow Activate", + "check multiwindow status for hiding subtitle", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:keep-external-fullscreen-post + * + * keep video-only mode for special case, it is set immediately. + */ + g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST, + g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen", + "set video-only mode forcedly for special case", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink:keep-external-fullscreen-prev + * + * keep video-only mode for special case, it is set in advance. + */ + g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV, + g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen", + "set video-only mode forcedly for special case", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXvImageSink::frame-render-error + */ + gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new ( + "frame-render-error", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + gst_xvimagesink_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); + /** + * GstXvImageSink::display-status + */ + gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new ( + "display-status", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + + /** + * GstXvImageSink::external-resolution + */ + gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new ( + "external-resolution", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + gst_marshal_VOID__INT_INT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + + /** + * GstXvImageSink::hided-window + */ + gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new ( + "hided-window", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + + /** + * GstXvImageSink::quick-panel-on + */ + gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new ( + "quick-panel-on", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + + /** + * GstXvImageSink::multiwindow-active + */ + gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new ( + "multiwindow-active", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + #endif /* GST_EXT_XV_ENHANCEMENT */ gobject_class->finalize = gst_xvimagesink_finalize; @@ -4879,3 +8138,5 @@ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, "xvimagesink", "XFree86 video output plugin using Xv extension", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) + + diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h old mode 100644 new mode 100755 index b3b0b5a..dfb9ed2 --- a/sys/xvimage/xvimagesink.h +++ b/sys/xvimage/xvimagesink.h @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <2005> Julien Moutte + * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -15,6 +16,11 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. + * + * * Modifications by Samsung Electronics Co., Ltd. + * 1. Add display related properties + * 2. Support samsung extension format to improve performance + * 3. Support video texture overlay of OSP layer */ #ifndef __GST_XVIMAGESINK_H__ @@ -40,6 +46,9 @@ #ifdef GST_EXT_XV_ENHANCEMENT #include #include +#include "xv_types.h" +#include +#include #endif #include @@ -60,8 +69,15 @@ G_BEGIN_DECLS (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK)) #ifdef GST_EXT_XV_ENHANCEMENT -#define XV_SCREEN_SIZE_WIDTH 4096 -#define XV_SCREEN_SIZE_HEIGHT 4096 +#define XV_SCREEN_SIZE_WIDTH 4096 +#define XV_SCREEN_SIZE_HEIGHT 4096 +#define DISPLAYING_BUFFERS_MAX_NUM 10 + +#define MAX_PIXMAP_NUM 10 +typedef uint (*get_pixmap_callback)(void *user_data); +typedef struct _GstXPixmap GstXPixmap; +typedef struct _GstXvImageDisplayingBuffer GstXvImageDisplayingBuffer; +typedef struct _GstXvImageFlushBuffer GstXvImageFlushBuffer; #endif /* GST_EXT_XV_ENHANCEMENT */ typedef struct _GstXContext GstXContext; @@ -162,6 +178,29 @@ struct _GstXWindow { GC gc; }; +#ifdef GST_EXT_XV_ENHANCEMENT +struct _GstXPixmap { + Window pixmap; + gint x, y; + gint width, height; + GC gc; +}; + +struct _GstXvImageDisplayingBuffer { + GstBuffer *buffer; + unsigned int dmabuf_fd[XV_BUF_PLANE_NUM]; + unsigned int gem_name[XV_BUF_PLANE_NUM]; + unsigned int gem_handle[XV_BUF_PLANE_NUM]; + void *bo[XV_BUF_PLANE_NUM]; + unsigned int ref_count; +}; + +struct _GstXvImageFlushBuffer { + unsigned int gem_name[XV_BUF_PLANE_NUM]; + void *bo[XV_BUF_PLANE_NUM]; +}; +#endif + /** * GstXvImageFormat: * @format: the image format @@ -199,8 +238,15 @@ struct _GstXvImageBuffer { gint width, height, im_format; size_t size; +#ifdef GST_EXT_XV_ENHANCEMENT + GstBuffer *current_buffer; +#endif /* GST_EXT_XV_ENHANCEMENT */ }; +#ifdef GST_EXT_XV_ENHANCEMENT +#define MAX_PLANE_NUM 4 +#endif /* GST_EXT_XV_ENHANCEMENT */ + /** * GstXvImageSink: * @display_name: the name of the Display we want to render to @@ -248,6 +294,10 @@ struct _GstXvImageSink { GstXWindow *xwindow; GstXvImageBuffer *xvimage; GstXvImageBuffer *cur_image; +#ifdef GST_EXT_XV_ENHANCEMENT + GstXvImageBuffer *last_image; + unsigned int last_image_vaddr[4]; +#endif GThread *event_thread; gboolean running; @@ -288,14 +338,14 @@ struct _GstXvImageSink { /* port attributes */ gboolean autopaint_colorkey; gint colorkey; - + gboolean draw_borders; - + /* port features */ gboolean have_autopaint_colorkey; gboolean have_colorkey; gboolean have_double_buffer; - + /* stream metadata */ gchar *media_title; @@ -305,23 +355,94 @@ struct _GstXvImageSink { #ifdef GST_EXT_XV_ENHANCEMENT /* display mode */ + gboolean is_pixmap; + gboolean xid_updated; guint display_mode; + guint csc_range; guint display_geometry_method; + guint flip; guint rotate_angle; - gboolean rotate_changed; gboolean visible; - guint zoom; + gfloat zoom; + guint zoom_pos_x; + guint zoom_pos_y; guint rotation; guint rotate_cnt; + guint orientation; + guint dst_roi_mode; GstVideoRectangle dst_roi; XImage* xim_transparenter; guint scr_w, scr_h; gboolean stop_video; gboolean is_hided; + gboolean is_quick_panel_on; + gboolean is_multi_window; + gboolean is_during_seek; + GstVideoRectangle src_crop; + /* needed if fourcc is one if S series */ guint aligned_width; guint aligned_height; + gint drm_fd; + void *bufmgr; + + /* for using multiple pixmaps */ + GstXPixmap *xpixmap[MAX_PIXMAP_NUM]; + gint current_pixmap_idx; + get_pixmap_callback get_pixmap_cb; + void* get_pixmap_cb_user_data; + + /* for sync displaying buffers */ + GstXvImageDisplayingBuffer displaying_buffers[DISPLAYING_BUFFERS_MAX_NUM]; + GMutex *display_buffer_lock; + + /* buffer count check */ + guint displayed_buffer_count; + guint displaying_buffer_count; + + /* zero copy format */ + gboolean is_zero_copy_format; + + /* secure contents path */ + gint secure_path; + + /* DRM level */ + gint drm_level; + +#ifdef GST_EXT_ENABLE_HEVC + /* if needed combine planes data */ + gint need_combine_data; #endif + + /* display request time */ + struct timeval request_time[DISPLAYING_BUFFERS_MAX_NUM]; + + /* last added buffer index */ + gint last_added_buffer_index; + + /* flush buffer */ + GstXvImageFlushBuffer *flush_buffer; + gboolean enable_flush_buffer; + + /* subtitle format */ + Pixmap pixmap_for_subpicture; + gboolean is_subpicture_format; + gboolean set_overlay_for_subpicture_just_once; + gboolean subpicture; + gboolean is_hided_subpicture; + gboolean is_quick_panel_on_subpicture; + gboolean is_multi_window_subpicture; + + /* external display */ + gint external_width; + gint external_height; + gboolean skip_frame_due_to_external_dev; + gboolean keep_external_fullscreen_post; + gboolean keep_external_fullscreen_prev; + + gboolean eos_received; + +#endif /* GST_EXT_XV_ENHANCEMENT */ }; #ifdef GST_EXT_XV_ENHANCEMENT diff --git a/tools/Makefile.am b/tools/Makefile.am index 647b634..278b4b0 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -19,7 +19,7 @@ LDADD = $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la\ $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la\ $(GST_BASE_LIBS) $(GST_LIBS) -AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) -pie # generate versioned scripts from templates %-@GST_MAJORMINOR@: %-m.m -- 2.7.4