diff --git a/.gitignore b/.gitignore
index 9b4f7f0373cd9..c29bcdf3c9361 100644
--- a/.gitignore
+++ b/.gitignore
@@ -591,6 +591,8 @@ lib/cmyth/Makefile
/xbmc/cores/amlplayer/Makefile
/xbmc/cores/omxplayer/Makefile
+/xbmc/utils/Makefile
+
# /lib/ffmpeg/
/lib/ffmpeg/config.h
/lib/ffmpeg/config.err
@@ -1099,6 +1101,7 @@ lib/cmyth/Makefile
# /xbmc/network/
/xbmc/network/Makefile
+/xbmc/network/linux/Makefile
/xbmc/network/upnp/Makefile
# /lib/libRTV/
diff --git a/Makefile.in b/Makefile.in
index 39dc6f9000ff0..4d438d93b3cb4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -77,6 +77,7 @@ DIRECTORY_ARCHIVES=$(DVDPLAYER_ARCHIVES) \
xbmc/pvr/timers/pvrtimers.a \
xbmc/pvr/windows/pvrwindows.a \
xbmc/rendering/rendering.a \
+ xbmc/security/security.a \
xbmc/settings/settings.a \
xbmc/storage/storage.a \
xbmc/utils/utils.a \
diff --git a/addons/skin.confluence/720p/DialogAccessPoints.xml b/addons/skin.confluence/720p/DialogAccessPoints.xml
new file mode 100644
index 0000000000000..8da2799a7f910
--- /dev/null
+++ b/addons/skin.confluence/720p/DialogAccessPoints.xml
@@ -0,0 +1,179 @@
+
+ 3
+ dialogeffect
+
+
+ 340
+ 110
+ 600
+ 500
+
+ background image
+ 0
+ 0
+ 600
+ 500
+ DialogBack.png
+ ![Window.IsVisible(FullscreenVideo) | Window.IsVisible(Visualisation)]
+
+
+ background image
+ 0
+ 0
+ 600
+ 500
+ DialogBack2.png
+ Window.IsVisible(FullscreenVideo) | Window.IsVisible(Visualisation)
+
+
+ Dialog Header image
+ 40
+ 16
+ 520
+ 40
+ dialogheader.png
+
+
+ heading label
+ 40
+ 20
+ 520
+ 30
+ font13_title
+
+ center
+ center
+ selected
+ black
+
+
+ Close Window button
+ 510
+ 15
+ 64
+ 32
+
+ -
+ PreviousMenu
+ DialogCloseButton-focus.png
+ DialogCloseButton.png
+ 3
+ 3
+ 3
+ 3
+ system.getbool(input.enablemouse)
+
+
+ 20
+ 70
+ 530
+ 400
+ 3
+ 3
+ 61
+ 61
+ 61
+ 200
+
+
+ 0
+ 0
+ 530
+ 40
+ MenuItemNF.png
+
+
+ 475
+ 10
+ 20
+ 20
+ !IsEmpty(ListItem.Property(encryption))
+ ap-lock.png
+
+
+ 440
+ 5
+ 30
+ 30
+ ap-signal$INFO[ListItem.Property(signal)].png
+
+
+ 0
+ 0
+ 40
+ 40
+ $INFO[ListItem.Property(state)].png
+
+
+ 40
+ 0
+ 490
+ 40
+ font13
+ grey2
+ left
+ center
+
+
+
+
+
+ 0
+ 0
+ 530
+ 40
+ MenuItemFO.png
+
+
+ 475
+ 10
+ 20
+ 20
+ !IsEmpty(ListItem.Property(encryption))
+ ap-lock.png
+
+
+ 440
+ 5
+ 30
+ 30
+ ap-signal$INFO[ListItem.Property(signal)].png
+
+
+ 0
+ 0
+ 40
+ 40
+ $INFO[ListItem.Property(state)].png
+
+
+ 40
+ 0
+ 490
+ 40
+ font13
+ selected
+ left
+ center
+
+
+
+
+
+ 555
+ 70
+ 25
+ 400
+ ScrollBarV.png
+ ScrollBarV_bar.png
+ ScrollBarV_bar_focus.png
+ ScrollBarNib.png
+ ScrollBarNib.png
+ 3
+ 3
+ false
+ vertical
+
+
+
+
diff --git a/addons/skin.confluence/media/Makefile.in b/addons/skin.confluence/media/Makefile.in
index 3cf7d1bcd30c5..bfb18c54537fd 100644
--- a/addons/skin.confluence/media/Makefile.in
+++ b/addons/skin.confluence/media/Makefile.in
@@ -10,7 +10,7 @@ all: $(TARGET)
.PHONY: force
$(TARGET): $(XBMCTEX) $(IMAGES)
-ifeq (@USE_ANDROID@,1)
+ifeq (@ARCH@,arm)
$(XBMCTEX) -use_none -input . -output $(TARGET)
else
$(XBMCTEX) -input . -output $(TARGET)
diff --git a/addons/skin.confluence/media/ap-lock.png b/addons/skin.confluence/media/ap-lock.png
new file mode 100644
index 0000000000000..2ebc4f6f9663e
Binary files /dev/null and b/addons/skin.confluence/media/ap-lock.png differ
diff --git a/addons/skin.confluence/media/ap-signal1.png b/addons/skin.confluence/media/ap-signal1.png
new file mode 100644
index 0000000000000..f53d5cfa4aeb5
Binary files /dev/null and b/addons/skin.confluence/media/ap-signal1.png differ
diff --git a/addons/skin.confluence/media/ap-signal2.png b/addons/skin.confluence/media/ap-signal2.png
new file mode 100644
index 0000000000000..d760d5b333d2f
Binary files /dev/null and b/addons/skin.confluence/media/ap-signal2.png differ
diff --git a/addons/skin.confluence/media/ap-signal3.png b/addons/skin.confluence/media/ap-signal3.png
new file mode 100644
index 0000000000000..39fb84e29307a
Binary files /dev/null and b/addons/skin.confluence/media/ap-signal3.png differ
diff --git a/addons/skin.confluence/media/ap-signal4.png b/addons/skin.confluence/media/ap-signal4.png
new file mode 100644
index 0000000000000..d4ec0969c560a
Binary files /dev/null and b/addons/skin.confluence/media/ap-signal4.png differ
diff --git a/addons/skin.confluence/media/ap-signal5.png b/addons/skin.confluence/media/ap-signal5.png
new file mode 100644
index 0000000000000..5b833bd44b327
Binary files /dev/null and b/addons/skin.confluence/media/ap-signal5.png differ
diff --git a/addons/skin.confluence/media/connected.png b/addons/skin.confluence/media/connected.png
new file mode 100644
index 0000000000000..d98f5e0e943f7
Binary files /dev/null and b/addons/skin.confluence/media/connected.png differ
diff --git a/addons/skin.confluence/media/connecting.png b/addons/skin.confluence/media/connecting.png
new file mode 100644
index 0000000000000..4e985f18a536f
Binary files /dev/null and b/addons/skin.confluence/media/connecting.png differ
diff --git a/addons/skin.confluence/media/disconnected.png b/addons/skin.confluence/media/disconnected.png
new file mode 100644
index 0000000000000..437debc07b1d7
Binary files /dev/null and b/addons/skin.confluence/media/disconnected.png differ
diff --git a/configure.in b/configure.in
index 476931559a212..f037c2f496370 100644
--- a/configure.in
+++ b/configure.in
@@ -30,6 +30,21 @@ AC_DEFUN([XB_ADD_PLAYER],
esac
])
+# check for enabling additional codecs
+AC_DEFUN([XB_ADD_CODEC],
+[
+ AC_MSG_CHECKING([for $2])
+ case $add_codecs in
+ *$2*)
+ AC_SUBST([USE_$1], 1)
+ AC_DEFINE([HAS_$1], 1, [using $2])
+ AC_MSG_RESULT([enabling $2])
+ ;;
+ *)
+ AC_MSG_RESULT([$2 is not enabled])
+ esac
+])
+
# check for library basenames
AC_DEFUN([XB_FIND_SONAME],
[
@@ -507,6 +522,12 @@ AC_ARG_ENABLE([gtest],
[configure_gtest=$enableval],
[configure_gtest=no])
+AC_ARG_ENABLE([codec],
+ [AS_HELP_STRING([--enable-codec],
+ [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec)])],
+ [add_codecs=$enableval],
+ [add_codecs=no])
+
### External libraries options
AC_ARG_ENABLE([external-libraries],
[AS_HELP_STRING([--enable-external-libraries],
@@ -622,10 +643,12 @@ case $host in
AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -D_POWERPC64")
;;
arm*-*-linux-gnu*)
- use_texturepacker=no
+ use_texturepacker_native=yes
ARCH="arm"
use_arch="arm"
AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_LINUX")
+ CFLAGS="$CFLAGS -Wno-psabi -Wa,-mno-warn-deprecated"
+ CXXFLAGS="$CXXFLAGS -Wno-psabi -Wa,-mno-warn-deprecated"
;;
arm*-*linux-android*)
target_platform=target_android
@@ -1830,6 +1853,14 @@ case $add_players in
;;
esac
+# additional internal codecs
+case $add_codecs in
+ *amcodec*)
+ AC_CHECK_HEADER([amlplayer/codec_error.h],, AC_MSG_ERROR($missing_headers))
+ XB_ADD_CODEC([LIBAMCODEC], [amcodec])
+ ;;
+esac
+
# platform specific bin utilities
if test "$host_vendor" != "apple" ; then
AC_CHECK_PROG(HAVE_GAWK,gawk,"yes","no",)
@@ -2283,11 +2314,17 @@ else
fi
if test "x$add_players" != "xno"; then
- final_message="$final_message\n additional players:\tYes"
+ final_message="$final_message\n additional players:\tYes, $add_players"
else
final_message="$final_message\n additional players:\tNo"
fi
+if test "x$add_codecs" != "xno"; then
+ final_message="$final_message\n additional codecs:\tYes, $add_codecs"
+else
+ final_message="$final_message\n additional codecs:\tNo"
+fi
+
### External libraries messages
if test "$use_external_ffmpeg" = "yes"; then
@@ -2355,6 +2392,7 @@ OUTPUT_FILES="Makefile \
xbmc/guilib/Makefile \
xbmc/interfaces/Makefile \
xbmc/network/Makefile \
+ xbmc/network/linux/Makefile \
xbmc/network/upnp/Makefile \
lib/libRTV/Makefile \
lib/libexif/Makefile \
@@ -2387,7 +2425,8 @@ OUTPUT_FILES="Makefile \
xbmc/peripherals/devices/Makefile \
xbmc/android/activity/Makefile \
xbmc/android/loader/Makefile \
- xbmc/main/Makefile"
+ xbmc/main/Makefile \
+ xbmc/utils/Makefile"
if test "$use_skin_touched" = "yes"; then
OUTPUT_FILES="$OUTPUT_FILES addons/skin.touched/media/Makefile"
diff --git a/language/English/strings.po b/language/English/strings.po
index dff2978eed0c7..6be1244943b1b 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -2555,7 +2555,9 @@ msgctxt "#713"
msgid "HTTP proxy"
msgstr ""
-#empty string with id 714
+msgctxt "#714"
+msgid "- Network Connection"
+msgstr ""
msgctxt "#715"
msgid "- Assignment"
@@ -11015,8 +11017,20 @@ msgctxt "#33200"
msgid "Detected New Connection"
msgstr ""
-#empty strings from id 33201 to 33999
+msgctxt "#33201"
+msgid "Available connections"
+msgstr ""
+
+msgctxt "#33202"
+msgid "Disconnected"
+msgstr ""
+
+msgctxt "#33203"
+msgid "Connecting"
+msgstr ""
+
#translators: no need to add these to your language files
+#empty strings from id 33204 to 33999
msgctxt "#34000"
msgid "Lame"
diff --git a/lib/ffmpeg/libavformat/rtpdec_h264.c b/lib/ffmpeg/libavformat/rtpdec_h264.c
index 730ed14807828..d8c87f4d6ef9c 100644
--- a/lib/ffmpeg/libavformat/rtpdec_h264.c
+++ b/lib/ffmpeg/libavformat/rtpdec_h264.c
@@ -113,7 +113,7 @@ static int sdp_parse_fmtp_config_h264(AVStream * stream,
h264_data->level_idc = level_idc;
}
} else if (!strcmp(attr, "sprop-parameter-sets")) {
- uint8_t start_sequence[]= { 0, 0, 1 };
+ uint8_t start_sequence[]= { 0, 0, 0, 1 };
codec->extradata_size= 0;
codec->extradata= NULL;
@@ -176,7 +176,7 @@ static int h264_handle_packet(AVFormatContext *ctx,
uint8_t nal = buf[0];
uint8_t type = (nal & 0x1f);
int result= 0;
- uint8_t start_sequence[]= {0, 0, 1};
+ uint8_t start_sequence[]= {0, 0, 0, 1};
#ifdef DEBUG
assert(data);
diff --git a/lib/ffmpeg/libavformat/rtsp.c b/lib/ffmpeg/libavformat/rtsp.c
index 2fccea1bea37f..9714695eb02f9 100644
--- a/lib/ffmpeg/libavformat/rtsp.c
+++ b/lib/ffmpeg/libavformat/rtsp.c
@@ -403,7 +403,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
break;
case 'a':
if (av_strstart(p, "control:", &p)) {
- if (s->nb_streams == 0) {
+ if (rt->nb_rtsp_streams == 0) {
if (!strncmp(p, "rtsp://", 7))
av_strlcpy(rt->control_uri, p,
sizeof(rt->control_uri));
diff --git a/lib/ffmpeg/libavformat/rtsp.h b/lib/ffmpeg/libavformat/rtsp.h
index f67ceb89cad03..fa607bbc46ea2 100644
--- a/lib/ffmpeg/libavformat/rtsp.h
+++ b/lib/ffmpeg/libavformat/rtsp.h
@@ -35,8 +35,8 @@
* Network layer over which RTP/etc packet data will be transported.
*/
enum RTSPLowerTransport {
- RTSP_LOWER_TRANSPORT_UDP = 0, /**< UDP/unicast */
- RTSP_LOWER_TRANSPORT_TCP = 1, /**< TCP; interleaved in RTSP */
+ RTSP_LOWER_TRANSPORT_TCP = 0, /**< TCP; interleaved in RTSP */
+ RTSP_LOWER_TRANSPORT_UDP = 1, /**< UDP/unicast */
RTSP_LOWER_TRANSPORT_UDP_MULTICAST = 2, /**< UDP/multicast */
RTSP_LOWER_TRANSPORT_NB,
RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper
diff --git a/lib/ffmpeg/patches/0036-rtp-use-four-byte-startcodes.patch b/lib/ffmpeg/patches/0036-rtp-use-four-byte-startcodes.patch
new file mode 100644
index 0000000000000..48a1cdd32eaed
--- /dev/null
+++ b/lib/ffmpeg/patches/0036-rtp-use-four-byte-startcodes.patch
@@ -0,0 +1,23 @@
+diff --git a/lib/ffmpeg/libavformat/rtpdec_h264.c b/lib/ffmpeg/libavformat/rtpdec_h264.c
+index 730ed14..d8c87f4 100644
+--- a/lib/ffmpeg/libavformat/rtpdec_h264.c
++++ b/lib/ffmpeg/libavformat/rtpdec_h264.c
+@@ -113,7 +113,7 @@ static int sdp_parse_fmtp_config_h264(AVStream * stream,
+ h264_data->level_idc = level_idc;
+ }
+ } else if (!strcmp(attr, "sprop-parameter-sets")) {
+- uint8_t start_sequence[]= { 0, 0, 1 };
++ uint8_t start_sequence[]= { 0, 0, 0, 1 };
+ codec->extradata_size= 0;
+ codec->extradata= NULL;
+
+@@ -176,7 +176,7 @@ static int h264_handle_packet(AVFormatContext *ctx,
+ uint8_t nal = buf[0];
+ uint8_t type = (nal & 0x1f);
+ int result= 0;
+- uint8_t start_sequence[]= {0, 0, 1};
++ uint8_t start_sequence[]= {0, 0, 0, 1};
+
+ #ifdef DEBUG
+ assert(data);
+
diff --git a/lib/ffmpeg/patches/0037-rtp-try-tcp-first.patch b/lib/ffmpeg/patches/0037-rtp-try-tcp-first.patch
new file mode 100644
index 0000000000000..9405404fa19f8
--- /dev/null
+++ b/lib/ffmpeg/patches/0037-rtp-try-tcp-first.patch
@@ -0,0 +1,16 @@
+diff --git a/lib/ffmpeg/libavformat/rtsp.h b/lib/ffmpeg/libavformat/rtsp.h
+index f67ceb8..fa607bb 100644
+--- a/lib/ffmpeg/libavformat/rtsp.h
++++ b/lib/ffmpeg/libavformat/rtsp.h
+@@ -35,8 +35,8 @@
+ * Network layer over which RTP/etc packet data will be transported.
+ */
+ enum RTSPLowerTransport {
+- RTSP_LOWER_TRANSPORT_UDP = 0, /**< UDP/unicast */
+- RTSP_LOWER_TRANSPORT_TCP = 1, /**< TCP; interleaved in RTSP */
++ RTSP_LOWER_TRANSPORT_TCP = 0, /**< TCP; interleaved in RTSP */
++ RTSP_LOWER_TRANSPORT_UDP = 1, /**< UDP/unicast */
+ RTSP_LOWER_TRANSPORT_UDP_MULTICAST = 2, /**< UDP/multicast */
+ RTSP_LOWER_TRANSPORT_NB,
+ RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper
+
diff --git a/lib/ffmpeg/patches/0038-rtp-fix-nb_rtsp_streams-bug-on-send-SETUP-cmd.patch b/lib/ffmpeg/patches/0038-rtp-fix-nb_rtsp_streams-bug-on-send-SETUP-cmd.patch
new file mode 100644
index 0000000000000..b8b3cd5593aad
--- /dev/null
+++ b/lib/ffmpeg/patches/0038-rtp-fix-nb_rtsp_streams-bug-on-send-SETUP-cmd.patch
@@ -0,0 +1,14 @@
+diff --git a/lib/ffmpeg/libavformat/rtsp.c b/lib/ffmpeg/libavformat/rtsp.c
+index 2fccea1..9714695 100644
+--- a/lib/ffmpeg/libavformat/rtsp.c
++++ b/lib/ffmpeg/libavformat/rtsp.c
+@@ -403,7 +403,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
+ break;
+ case 'a':
+ if (av_strstart(p, "control:", &p)) {
+- if (s->nb_streams == 0) {
++ if (rt->nb_rtsp_streams == 0) {
+ if (!strncmp(p, "rtsp://", 7))
+ av_strlcpy(rt->control_uri, p,
+ sizeof(rt->control_uri));
+
diff --git a/lib/libdvd/libdvdnav/Makefile b/lib/libdvd/libdvdnav/Makefile
index 85245b7a4d764..8b743463d7397 100644
--- a/lib/libdvd/libdvdnav/Makefile
+++ b/lib/libdvd/libdvdnav/Makefile
@@ -21,7 +21,7 @@ CFLAGS += -DHAVE_CONFIG_H -DHAVE_DLFCN_H
L=libdvdnav
MINI_L=libdvdnavmini
-CFLAGS += $(DVDREAD_CFLAGS)
+#CFLAGS += $(DVDREAD_CFLAGS)
LIB = $(L).a
SHLIB = $(L).so
diff --git a/lib/libdvd/libdvdread/src/dvd_reader.c b/lib/libdvd/libdvdread/src/dvd_reader.c
index 8849e848e3725..5ea16c4f73ddc 100644
--- a/lib/libdvd/libdvdread/src/dvd_reader.c
+++ b/lib/libdvd/libdvdread/src/dvd_reader.c
@@ -248,6 +248,7 @@ static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css )
dvdinput_close(dev);
return NULL;
}
+ memset( dvd, 0, sizeof( dvd_reader_t ) );
dvd->isImageFile = 1;
dvd->dev = dev;
dvd->path_root = NULL;
@@ -495,6 +496,8 @@ dvd_reader_t *DVDOpen( const char *ppath )
fclose( mntfile );
}
#elif defined(__linux__)
+ /* amlogic/linux hack, tries to use /root as a device, wtf? */
+ if (strcmp("/root", path_copy )) {
mntfile = fopen( _PATH_MOUNTED, "r" );
if( mntfile ) {
struct mntent *me;
@@ -513,6 +516,7 @@ dvd_reader_t *DVDOpen( const char *ppath )
}
fclose( mntfile );
}
+ }
#elif defined(_MSC_VER)
auth_drive = DVDOpenImageFile( path, have_css );
#endif
diff --git a/system/playercorefactory.xml b/system/playercorefactory.xml
index 76027b6315ed1..9992693a0fdfb 100644
--- a/system/playercorefactory.xml
+++ b/system/playercorefactory.xml
@@ -11,7 +11,7 @@
-
+
@@ -25,6 +25,7 @@
+
@@ -35,5 +36,9 @@
+
+
+
+
diff --git a/system/shaders/guishader_frag_multi_blendcolor.glsl b/system/shaders/guishader_frag_multi_blendcolor.glsl
index b311350ff96fa..58c3e55801291 100644
--- a/system/shaders/guishader_frag_multi_blendcolor.glsl
+++ b/system/shaders/guishader_frag_multi_blendcolor.glsl
@@ -24,10 +24,10 @@ uniform sampler2D m_samp0;
uniform sampler2D m_samp1;
varying vec4 m_cord0;
varying vec4 m_cord1;
-varying lowp vec4 m_colour;
+uniform lowp vec4 m_unicol;
// SM_MULTI shader
void main ()
{
- gl_FragColor.rgba = (texture2D(m_samp0, m_cord0.xy) * texture2D(m_samp1, m_cord1.xy)).rgba * m_colour;
+ gl_FragColor.rgba = m_unicol * texture2D(m_samp0, m_cord0.xy) * texture2D(m_samp1, m_cord1.xy);
}
diff --git a/system/shaders/guishader_frag_texture.glsl b/system/shaders/guishader_frag_texture.glsl
index 16bb84e442d0c..fbce8a3166296 100644
--- a/system/shaders/guishader_frag_texture.glsl
+++ b/system/shaders/guishader_frag_texture.glsl
@@ -21,11 +21,11 @@
precision mediump float;
uniform sampler2D m_samp0;
+uniform lowp vec4 m_unicol;
varying vec4 m_cord0;
-varying lowp vec4 m_colour;
// SM_TEXTURE shader
void main ()
{
- gl_FragColor.rgba = vec4(texture2D(m_samp0, m_cord0.xy).rgba * m_colour);
+ gl_FragColor.rgba = vec4(texture2D(m_samp0, m_cord0.xy).rgba * m_unicol);
}
diff --git a/tools/amlogic/depends/xbmc/Makefile b/tools/amlogic/depends/xbmc/Makefile
new file mode 100644
index 0000000000000..94185efe100a8
--- /dev/null
+++ b/tools/amlogic/depends/xbmc/Makefile
@@ -0,0 +1,3 @@
+export SOURCE=$(CURDIR)/../../../..
+all:
+ $(MAKE) -I $(BUILDROOT) -f xbmc.mk
diff --git a/tools/amlogic/depends/xbmc/buildroot-sdk.mk b/tools/amlogic/depends/xbmc/buildroot-sdk.mk
new file mode 100644
index 0000000000000..1e3509116c594
--- /dev/null
+++ b/tools/amlogic/depends/xbmc/buildroot-sdk.mk
@@ -0,0 +1,54 @@
+qstrip=$(strip $(subst ",,$(1)))#"))
+-include $(BUILDROOT)/.config
+-include $(BUILDROOT)/toolchain/gcc/Makefile.in
+BASE_DIR=$(BUILDROOT)/output
+TOOLCHAIN_EXTERNAL_DIR=$(BASE_DIR)/external-toolchain
+ARCH=$(call qstrip,$(BR2_ARCH))
+HOST_DIR=$(call qstrip,$(BR2_HOST_DIR))
+HOST=$(call qstrip,$(BR2_TOOLCHAIN_EXTERNAL_PREFIX))
+PKG_CONFIG_HOST_BINARY=$(HOST_DIR)/usr/bin/pkg-config
+
+ifndef HOSTAR
+HOSTAR:=ar
+endif
+ifndef HOSTAS
+HOSTAS:=as
+endif
+ifndef HOSTCC
+HOSTCC:=gcc
+HOSTCC:=$(shell which $(HOSTCC) || type -p $(HOSTCC) || echo gcc)
+HOSTCC_NOCCACHE:=$(HOSTCC)
+endif
+ifndef HOSTCXX
+HOSTCXX:=g++
+HOSTCXX:=$(shell which $(HOSTCXX) || type -p $(HOSTCXX) || echo g++)
+HOSTCXX_NOCCACHE:=$(HOSTCXX)
+endif
+ifndef HOSTFC
+HOSTFC:=gfortran
+endif
+ifndef HOSTCPP
+HOSTCPP:=cpp
+endif
+ifndef HOSTLD
+HOSTLD:=ld
+endif
+ifndef HOSTLN
+HOSTLN:=ln
+endif
+ifndef HOSTNM
+HOSTNM:=nm
+endif
+HOSTAR:=$(shell which $(HOSTAR) || type -p $(HOSTAR) || echo ar)
+HOSTAS:=$(shell which $(HOSTAS) || type -p $(HOSTAS) || echo as)
+HOSTFC:=$(shell which $(HOSTLD) || type -p $(HOSTLD) || echo || which g77 || type -p g77 || echo gfortran)
+HOSTCPP:=$(shell which $(HOSTCPP) || type -p $(HOSTCPP) || echo cpp)
+HOSTLD:=$(shell which $(HOSTLD) || type -p $(HOSTLD) || echo ld)
+HOSTLN:=$(shell which $(HOSTLN) || type -p $(HOSTLN) || echo ln)
+HOSTNM:=$(shell which $(HOSTNM) || type -p $(HOSTNM) || echo nm)
+
+all:
+-include $(BUILDROOT)/package/Makefile.in
+-include $(BUILDROOT)/package/Makefile.autotools.in
+-include $(BUILDROOT)/package/Makefile.cmake.in
+-include $(BUILDROOT)/package/Makefile.package.in
diff --git a/tools/amlogic/depends/xbmc/xbmc.mk b/tools/amlogic/depends/xbmc/xbmc.mk
new file mode 100644
index 0000000000000..da2ae74b1bc6e
--- /dev/null
+++ b/tools/amlogic/depends/xbmc/xbmc.mk
@@ -0,0 +1,21 @@
+all: $(SOURCE)/xbmc.bin
+
+include buildroot-sdk.mk
+-include $(BUILDROOT)/package/python/python.mk
+-include $(BUILDROOT)/package/thirdparty/xbmc/xbmc.mk
+$(SOURCE)/xbmc.bin: $(SOURCE)/Makefile
+ cd $(SOURCE); $(MAKE)
+
+$(SOURCE)/Makefile: $(SOURCE)/configure
+ cd $(SOURCE); $(TARGET_CONFIGURE_OPTS) $(TARGET_CONFIGURE_ARGS) $(XBMC_CONF_ENV) \
+ ./configure --target=$(GNU_TARGET_NAME) --host=$(GNU_TARGET_NAME) --build=$(GNU_HOST_NAME) \
+ --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc $(XBMC_CONF_OPT) --disable-external-ffmpeg
+
+$(SOURCE)/configure: $(BUILDROOT)/package/thirdparty/xbmc/xbmc.mk $(GCC)
+ cd $(SOURCE); ./bootstrap
+
+$(GCC):
+ $(error gcc does not exist. Have you built Buildroot?)
+
+$(BUILDROOT)/package/thirdparty/xbmc/xbmc.mk:
+ $(error BUILDROOT must be defined in buildroot-sdk.mk)
diff --git a/tools/android/depends/libamplayer/libamplayer/include/codec.h b/tools/android/depends/libamplayer/libamplayer/include/codec.h
new file mode 100644
index 0000000000000..187d4d5c82531
--- /dev/null
+++ b/tools/android/depends/libamplayer/libamplayer/include/codec.h
@@ -0,0 +1,93 @@
+/**
+* @file codec.h
+* @brief Function prototypes of codec lib
+* @author Zhang Chen
+* @version 1.0.0
+* @date 2011-02-24
+*/
+/* Copyright (C) 2007-2011, Amlogic Inc.
+* All right reserved
+*
+*/
+#ifndef CODEC_CTRL_H_
+#define CODEC_CTRL_H_
+
+#include
+#include
+
+
+int codec_init(codec_para_t *);
+int codec_close(codec_para_t *);
+void codec_audio_basic_init(void);
+void codec_close_audio(codec_para_t *);
+void codec_resume_audio(codec_para_t *, unsigned int);
+int codec_reset(codec_para_t *);
+int codec_init_sub(codec_para_t *);
+int codec_open_sub_read(void);
+int codec_close_sub(codec_para_t *);
+int codec_close_sub_fd(CODEC_HANDLE);
+int codec_reset_subtile(codec_para_t *pcodec);
+int codec_poll_sub(codec_para_t *);
+int codec_poll_sub_fd(CODEC_HANDLE, int);
+int codec_get_sub_size(codec_para_t *);
+int codec_get_sub_size_fd(CODEC_HANDLE);
+int codec_read_sub_data(codec_para_t *, char *, unsigned int);
+int codec_read_sub_data_fd(CODEC_HANDLE, char *, unsigned int);
+int codec_write_sub_data(codec_para_t *, char *, unsigned int);
+int codec_init_cntl(codec_para_t *);
+int codec_close_cntl(codec_para_t *);
+int codec_poll_cntl(codec_para_t *);
+int codec_get_cntl_state(codec_para_t *);
+int codec_set_cntl_mode(codec_para_t *, unsigned int);
+int codec_set_cntl_avthresh(codec_para_t *, unsigned int);
+int codec_set_cntl_syncthresh(codec_para_t *pcodec, unsigned int syncthresh);
+int codec_reset_audio(codec_para_t *pcodec);
+int codec_set_audio_pid(codec_para_t *pcodec);
+int codec_set_sub_id(codec_para_t *pcodec);
+int codec_set_sub_type(codec_para_t *pcodec);
+int codec_audio_reinit(codec_para_t *pcodec);
+int codec_set_dec_reset(codec_para_t *pcodec);
+
+int codec_write(codec_para_t *pcodec, void *buffer, int len);
+int codec_checkin_pts(codec_para_t *pcodec, unsigned long pts);
+int codec_get_vbuf_state(codec_para_t *, struct buf_status *);
+int codec_get_abuf_state(codec_para_t *, struct buf_status *);
+int codec_get_vdec_state(codec_para_t *, struct vdec_status *);
+int codec_get_adec_state(codec_para_t *, struct adec_status *);
+
+int codec_pause(codec_para_t *);
+int codec_resume(codec_para_t *);
+int codec_audio_search(codec_para_t *p);
+int codec_set_mute(codec_para_t *p, int mute);
+int codec_get_volume_range(codec_para_t *, int *min, int *max);
+int codec_set_volume(codec_para_t *, float val);
+int codec_get_volume(codec_para_t *, float *val);
+int codec_set_lrvolume(codec_para_t *, float lvol,float rvol);
+int codec_get_lrvolume(codec_para_t *, float *lvol,float* rvol);
+int codec_get_mutesta(codec_para_t *);
+int codec_set_volume_balance(codec_para_t *, int); /*left£¨0-100)right*/
+int codec_swap_left_right(codec_para_t *);
+int codec_left_mono(codec_para_t *p);
+int codec_right_mono(codec_para_t *p);
+int codec_stereo(codec_para_t *p);
+int codec_get_soundtrack(codec_para_t *p,int* strack);
+int codec_audio_automute(void *priv, int auto_mute);
+int codec_audio_spectrum_switch(codec_para_t *p, int isStart, int interval);
+int codec_audio_isready(codec_para_t *p);
+int codec_audio_get_nb_frames(codec_para_t *p);
+int codec_audio_set_audioinfo(codec_para_t *p);
+
+int codec_get_apts(codec_para_t *pcodec);
+int codec_get_vpts(codec_para_t *pcodec);
+int codec_get_pcrscr(codec_para_t *pcodec);
+int codec_set_pcrscr(codec_para_t *pcodec, int val);
+int codec_set_syncenable(codec_para_t *pcodec, int enable);
+int codec_set_sync_audio_discont(codec_para_t *pcodec, int discontinue);
+int codec_get_sync_audio_discont(codec_para_t *pcodec);
+int codec_set_sync_video_discont(codec_para_t *pcodec, int discontinue);
+int codec_get_sync_video_discont(codec_para_t *pcodec);
+
+int codec_get_sub_num(codec_para_t *pcodec);
+int codec_get_sub_info(codec_para_t *pcodec, subtitle_info_t *sub_info);
+
+#endif
diff --git a/tools/android/depends/libamplayer/libamplayer/include/codec_error.h b/tools/android/depends/libamplayer/libamplayer/include/codec_error.h
new file mode 100644
index 0000000000000..0d6df8fdf4ff4
--- /dev/null
+++ b/tools/android/depends/libamplayer/libamplayer/include/codec_error.h
@@ -0,0 +1,37 @@
+/**
+* @file codec_error.h
+* @brief Codec error type definitions
+* @author Zhang Chen
+* @version 1.0.0
+* @date 2011-02-24
+*/
+/* Copyright (C) 2007-2011, Amlogic Inc.
+* All right reserved
+*
+*/
+
+#ifndef CODEC_ERROR_H_
+#define CODEC_ERROR_H_
+
+#define C_PAE (0x01000000)
+
+#define CODEC_ERROR_NONE ( 0)
+#define CODEC_ERROR_INVAL (C_PAE | 1)
+#define CODEC_ERROR_NOMEM (C_PAE | 2)
+#define CODEC_ERROR_BUSY (C_PAE | 3)
+#define CODEC_ERROR_IO (C_PAE | 4)
+#define CODEC_ERROR_PARAMETER (C_PAE | 5)
+#define CODEC_ERROR_AUDIO_TYPE_UNKNOW (C_PAE | 6)
+#define CODEC_ERROR_VIDEO_TYPE_UNKNOW (C_PAE | 7)
+#define CODEC_ERROR_STREAM_TYPE_UNKNOW (C_PAE | 8)
+#define CODEC_ERROR_VDEC_TYPE_UNKNOW (C_PAE | 9)
+
+#define CODEC_ERROR_INIT_FAILED (C_PAE | 10)
+#define CODEC_ERROR_SET_BUFSIZE_FAILED (C_PAE | 11)
+#define CODEC_OPEN_HANDLE_FAILED (C_PAE | 12)
+
+
+
+
+#endif
+
diff --git a/tools/android/depends/libamplayer/libamplayer/include/codec_msg.h b/tools/android/depends/libamplayer/libamplayer/include/codec_msg.h
new file mode 100644
index 0000000000000..f898af3756fa6
--- /dev/null
+++ b/tools/android/depends/libamplayer/libamplayer/include/codec_msg.h
@@ -0,0 +1,19 @@
+/**
+* @file codec_msg.h
+* @brief Function prototype of codec error
+* @author Zhang Chen
+* @version 1.0.0
+* @date 2011-02-24
+*/
+/* Copyright (C) 2007-2011, Amlogic Inc.
+* All right reserved
+*
+*/
+#ifndef CODEC_MSG_H
+#define CODEC_MSG_H
+
+const char * codec_error_msg(int error);
+int system_error_to_codec_error(int error);
+void print_error_msg(int error, int syserr, char *func, int line);
+
+#endif
diff --git a/tools/android/depends/libamplayer/libamplayer/include/codec_type.h b/tools/android/depends/libamplayer/libamplayer/include/codec_type.h
new file mode 100644
index 0000000000000..5d61ca8722312
--- /dev/null
+++ b/tools/android/depends/libamplayer/libamplayer/include/codec_type.h
@@ -0,0 +1,108 @@
+/**
+* @file codec_type.h
+* @brief Definitions of codec type and structures
+* @author Zhang Chen
+* @version 1.0.0
+* @date 2011-02-24
+*/
+/* Copyright (C) 2007-2011, Amlogic Inc.
+* All right reserved
+*
+*/
+#ifndef CODEC_TYPE_H_
+#define CODEC_TYPE_H_
+
+#include "amports/amstream.h"
+#include "amports/vformat.h"
+#include "amports/aformat.h"
+
+typedef int CODEC_HANDLE;
+
+typedef enum {
+ STREAM_TYPE_UNKNOW,
+ STREAM_TYPE_ES_VIDEO,
+ STREAM_TYPE_ES_AUDIO,
+ STREAM_TYPE_ES_SUB,
+ STREAM_TYPE_PS,
+ STREAM_TYPE_TS,
+ STREAM_TYPE_RM,
+} stream_type_t;
+
+typedef struct {
+ unsigned int format; ///< video format, such as H264, MPEG2...
+ unsigned int width; ///< video source width
+ unsigned int height; ///< video source height
+ unsigned int rate; ///< video source frame duration
+ unsigned int extra; ///< extra data information of video stream
+ unsigned int status; ///< status of video stream
+ unsigned int ratio; ///< aspect ratio of video source
+ void * param; ///< other parameters for video decoder
+ unsigned long long ratio64; ///< aspect ratio of video source
+} dec_sysinfo_t;
+
+typedef struct {
+ int valid; ///< audio extradata valid(1) or invalid(0), set by dsp
+ int sample_rate; ///< audio stream sample rate
+ int channels; ///< audio stream channels
+ int bitrate; ///< audio stream bit rate
+ int codec_id; ///< codec format id
+ int block_align; ///< audio block align from ffmpeg
+ int extradata_size; ///< extra data size
+ char extradata[AUDIO_EXTRA_DATA_SIZE]; ///< extra data information for decoder
+} audio_info_t;
+
+typedef struct {
+ CODEC_HANDLE handle; ///< codec device handler
+ CODEC_HANDLE cntl_handle; ///< video control device handler
+ CODEC_HANDLE sub_handle; ///< subtile device handler
+ stream_type_t stream_type; ///< stream type(es, ps, rm, ts)
+ unsigned int has_video:1; ///< stream has video(1) or not(0)
+ unsigned int has_audio:1; ///< stream has audio(1) or not(0)
+ unsigned int has_sub:1; ///< stream has subtitle(1) or not(0)
+ unsigned int noblock:1; ///< codec device is NONBLOCK(1) or not(0)
+ int video_type; ///< stream video type(H264, VC1...)
+ int audio_type; ///< stream audio type(PCM, WMA...)
+ int sub_type; ///< stream subtitle type(TXT, SSA...)
+ int video_pid; ///< stream video pid
+ int audio_pid; ///< stream audio pid
+ int sub_pid; ///< stream subtitle pid
+ int audio_channels; ///< stream audio channel number
+ int audio_samplerate; ///< steram audio sample rate
+ int vbuf_size; ///< video buffer size of codec device
+ int abuf_size; ///< audio buffer size of codec device
+ dec_sysinfo_t am_sysinfo; ///< system information for video
+ audio_info_t audio_info; ///< audio information pass to audiodsp
+ int packet_size; ///< data size per packet
+ int avsync_threshold; ///
+ void * adec_priv; ///
+} codec_para_t;
+
+typedef struct
+{
+ signed char id;
+ unsigned char width;
+ unsigned char height;
+ unsigned char type;
+} subtitle_info_t;
+#define MAX_SUB_NUM (32)
+
+#define IS_VALID_PID(t) (t>=0 && t<=0x1fff)
+#define IS_VALID_STREAM(t) (t>0 && t<=0x1fff)
+#define IS_VALID_ATYPE(t) (t>=0 && t=0 && t
#define MSG_SIZE 64
+#if defined(HAS_AMLPLAYER_CHAPTERS)
+#define MAX_CHAPTERS 64
+#endif
+#if defined(HAS_AMLPLAYER_VIDEO_STREAMS10)
+#define MAX_VIDEO_STREAMS 10
+#else
#define MAX_VIDEO_STREAMS 8
+#endif
#define MAX_AUDIO_STREAMS 8
#define MAX_SUB_INTERNAL 8
#define MAX_SUB_EXTERNAL 24
@@ -64,8 +71,6 @@ typedef enum
PLAYER_DIVX_AUTHORERR = 0x40001,
PLAYER_DIVX_RENTAL_EXPIRED = 0x40002,
PLAYER_DIVX_RENTAL_VIEW = 0x40003,
-
-
}player_status;
@@ -107,6 +112,7 @@ typedef struct
typedef struct
{
+ int index;
int id;
int channel;
int sample_rate;
@@ -114,10 +120,14 @@ typedef struct
aformat_t aformat;
int duration;
audio_tag_info *audio_tag;
+#if defined(HAS_AMLPLAYER_AUDIO_LANG)
+ char audio_language[4];
+#endif
}maudio_info_t;
typedef struct
{
+ int index;
char id;
char internal_external; //0:internal_sub 1:external_sub
unsigned short width;
@@ -147,14 +157,33 @@ typedef struct
int cur_sub_index;
int seekable;
int drm_check;
+#if defined(HAS_AMLPLAYER_VIDEO_STREAMS10)
+ int t1;
+ int t2;
+#endif
+#if defined(HAS_AMLPLAYER_CHAPTERS)
+ int has_chapter;
+ int total_chapter_num;
+#endif
}mstream_info_t;
+#if defined(HAS_AMLPLAYER_CHAPTERS)
+typedef struct
+{
+ char *name;
+ int64_t seekto_ms;
+} mchapter_info_t;
+#endif
+
typedef struct
{
mstream_info_t stream_info;
mvideo_info_t *video_info[MAX_VIDEO_STREAMS];
maudio_info_t *audio_info[MAX_AUDIO_STREAMS];
msub_info_t *sub_info[MAX_SUB_STREAMS];
+#if defined(HAS_AMLPLAYER_CHAPTERS)
+ mchapter_info_t *chapter_info[MAX_CHAPTERS];
+#endif
}media_info_t;
typedef struct player_info
@@ -213,8 +242,23 @@ typedef enum
PLAYER_EVENTS_ERROR, ////dev/null || git fetch origin "+refs/heads/*:refs/remotes/origin/*"
+ git rev-list -1 $(VERSION) >/dev/null
+ rm -rf $(GIT_DIR)/current; mkdir -p $(GIT_DIR)/current
+ touch $@
+
+$(PLATFORM)/bootstrap: $(GIT_DIR)/current/$(VERSION)
+ rm -rf $(PLATFORM); mkdir -p $(PLATFORM)
+ git checkout $(VERSION) -- .
+
+$(PLATFORM): $(PLATFORM)/bootstrap
+ cd $(PLATFORM); patch -p1 < ../librtmp-60-second-fix.patch
cd $(PLATFORM); patch -p0 < ../prefix.patch
$(LIBDYLIB): $(PLATFORM)
- $(MAKE) -C $(PLATFORM)/librtmp CROSS_COMPILE=$(CROSSTOOLS) PREFIX=$(PREFIX)
+ $(MAKE) -C $(PLATFORM)/librtmp CROSS_COMPILE=$(CROSSTOOLS) PREFIX=$(PREFIX) XCFLAGS="$(CFLAGS)" XLDFLAGS="$(LDFLAGS) -lm"
.installed-$(PLATFORM): $(LIBDYLIB)
$(MAKE) -C $(PLATFORM)/librtmp install PREFIX=$(PREFIX)
diff --git a/tools/android/depends/librtmp/librtmp-60-second-fix.patch b/tools/android/depends/librtmp/librtmp-60-second-fix.patch
new file mode 100644
index 0000000000000..2914fc1b8eb20
--- /dev/null
+++ b/tools/android/depends/librtmp/librtmp-60-second-fix.patch
@@ -0,0 +1,1913 @@
+diff --git a/librtmp/amf.c b/librtmp/amf.c
+index ce84f81..a25bc04 100644
+--- a/librtmp/amf.c
++++ b/librtmp/amf.c
+@@ -610,6 +610,9 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
+ return -1;
+ }
+
++ if (*pBuffer == AMF_NULL)
++ bDecodeName = 0;
++
+ if (bDecodeName && nSize < 4)
+ { /* at least name (length + at least 1 byte) and 1 byte of data */
+ RTMP_Log(RTMP_LOGDEBUG,
+@@ -801,8 +804,8 @@ AMFProp_Dump(AMFObjectProperty *prop)
+ }
+ else
+ {
+- name.av_val = "no-name.";
+- name.av_len = sizeof("no-name.") - 1;
++ name.av_val = "no-name";
++ name.av_len = sizeof("no-name") - 1;
+ }
+ if (name.av_len > 18)
+ name.av_len = 18;
+diff --git a/librtmp/dh.h b/librtmp/dh.h
+index 9959532..e29587b 100644
+--- a/librtmp/dh.h
++++ b/librtmp/dh.h
+@@ -61,7 +61,7 @@ static int MDH_generate_key(MDH *dh)
+ MP_set(&dh->ctx.P, dh->p);
+ MP_set(&dh->ctx.G, dh->g);
+ dh->ctx.len = 128;
+- dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs);
++ dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs);
+ MP_new(dh->pub_key);
+ MP_new(dh->priv_key);
+ MP_set(dh->pub_key, &dh->ctx.GX);
+diff --git a/librtmp/handshake.h b/librtmp/handshake.h
+index 0438486..102ba82 100644
+--- a/librtmp/handshake.h
++++ b/librtmp/handshake.h
+@@ -965,8 +965,18 @@ HandShake(RTMP * r, int FP9HandShake)
+ __FUNCTION__);
+ RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE);
+ #endif
+- if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE))
+- return FALSE;
++ if (r->Link.CombineConnectPacket)
++ {
++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE);
++ memcpy(HandshakeResponse, (char *) reply, RTMP_SIG_SIZE);
++ r->Link.HandshakeResponse.av_val = HandshakeResponse;
++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE;
++ }
++ else
++ {
++ if (!WriteN(r, (char *) reply, RTMP_SIG_SIZE))
++ return FALSE;
++ }
+
+ /* 2nd part of handshake */
+ if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+diff --git a/librtmp/hashswf.c b/librtmp/hashswf.c
+index 9f4e2c0..eeed34c 100644
+--- a/librtmp/hashswf.c
++++ b/librtmp/hashswf.c
+@@ -70,7 +70,7 @@ extern TLS_CTX RTMP_TLS_ctx;
+
+ #endif /* CRYPTO */
+
+-#define AGENT "Mozilla/5.0"
++#define AGENT "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0"
+
+ HTTPResult
+ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
+@@ -528,7 +528,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
+
+ if (strncmp(buf, "url: ", 5))
+ continue;
+- if (strncmp(buf + 5, url, hlen))
++ if (strncmp(buf + 5, url, strlen(buf + 5) - 1))
+ continue;
+ r1 = strrchr(buf, '/');
+ i = strlen(r1);
+diff --git a/librtmp/log.c b/librtmp/log.c
+index 0012985..856e3e4 100644
+--- a/librtmp/log.c
++++ b/librtmp/log.c
+@@ -52,8 +52,8 @@ static void rtmp_log_default(int level, const char *format, va_list vl)
+ vsnprintf(str, MAX_PRINT_LEN-1, format, vl);
+
+ /* Filter out 'no-name' */
+- if ( RTMP_debuglevel
+ #include
+ #include
++#include
+
+ #include "rtmp_sys.h"
+ #include "log.h"
+@@ -45,6 +46,7 @@ TLS_CTX RTMP_TLS_ctx;
+
+ #define RTMP_SIG_SIZE 1536
+ #define RTMP_LARGE_HEADER_SIZE 12
++#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
+
+ static const int packetSize[] = { 12, 8, 4, 1 };
+
+@@ -97,6 +99,9 @@ static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
+ static int SendPlay(RTMP *r);
+ static int SendBytesReceived(RTMP *r);
+ static int SendUsherToken(RTMP *r, AVal *usherToken);
++static int SendInvoke(RTMP *r, AVal *Command, int queue);
++static int SendGetStreamLength(RTMP *r);
++static int strsplit(char *src, int srclen, char delim, char ***params);
+
+ #if 0 /* unused */
+ static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
+@@ -259,6 +264,8 @@ RTMP_Init(RTMP *r)
+ r->m_fVideoCodecs = 252.0;
+ r->Link.timeout = 30;
+ r->Link.swfAge = 30;
++ r->Link.CombineConnectPacket = TRUE;
++ r->Link.ConnectPacket = FALSE;
+ }
+
+ void
+@@ -337,6 +344,7 @@ RTMP_SetupStream(RTMP *r,
+ AVal *flashVer,
+ AVal *subscribepath,
+ AVal *usherToken,
++ AVal *WeebToken,
+ int dStart,
+ int dStop, int bLiveStream, long int timeout)
+ {
+@@ -359,6 +367,8 @@ RTMP_SetupStream(RTMP *r,
+ RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
+ if (usherToken && usherToken->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
++ if (WeebToken && WeebToken->av_val)
++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", WeebToken->av_val);
+ if (flashVer && flashVer->av_val)
+ RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
+ if (dStart > 0)
+@@ -426,6 +436,8 @@ RTMP_SetupStream(RTMP *r,
+ r->Link.subscribepath = *subscribepath;
+ if (usherToken && usherToken->av_len)
+ r->Link.usherToken = *usherToken;
++ if (WeebToken && WeebToken->av_len)
++ r->Link.WeebToken = *WeebToken;
+ r->Link.seekTime = dStart;
+ r->Link.stopTime = dStop;
+ if (bLiveStream)
+@@ -483,14 +495,22 @@ static struct urlopt {
+ "Stream is live, no seeking possible" },
+ { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
+ "Stream to subscribe to" },
+- { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
+- "Justin.tv authentication token" },
+- { AVC("token"), OFF(Link.token), OPT_STR, 0,
++ { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
++ "Justin.tv authentication token"},
++ { AVC("weeb"), OFF(Link.WeebToken), OPT_STR, 0,
++ "Weeb.tv authentication token"},
++ { AVC("token"), OFF(Link.token), OPT_STR, 0,
+ "Key for SecureToken response" },
+ { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
+ "Perform SWF Verification" },
+ { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
+ "Number of days to use cached SWF hash" },
++#ifdef CRYPTO
++ { AVC("swfsize"), OFF(Link.swfSize), OPT_INT, 0,
++ "Size of the decompressed SWF file"},
++ { AVC("swfhash"), OFF(Link.swfHash), OPT_STR, 0,
++ "SHA256 hash of the decompressed SWF file"},
++#endif
+ { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
+ "Stream start position in milliseconds" },
+ { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
+@@ -751,9 +771,16 @@ int RTMP_SetupURL(RTMP *r, char *url)
+ }
+
+ #ifdef CRYPTO
+- if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
+- RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
+- (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %d %d %s\n", r->Link.swfSize, r->Link.swfHash.av_len, r->Link.swfHash.av_val);
++ if (r->Link.swfSize && r->Link.swfHash.av_len)
++ {
++ int i, j = 0;
++ for (i = 0; i < r->Link.swfHash.av_len; i += 2)
++ r->Link.SWFHash[j++] = (HEX2BIN(r->Link.swfHash.av_val[i]) << 4) | HEX2BIN(r->Link.swfHash.av_val[i + 1]);
++ r->Link.SWFSize = (uint32_t) r->Link.swfSize;
++ }
++ else if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
++ RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, (unsigned char *) r->Link.SWFHash, r->Link.swfAge);
+ #endif
+
+ if (r->Link.port == 0)
+@@ -854,6 +881,8 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service)
+ }
+
+ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
++ if (r->Link.protocol & RTMP_FEATURE_HTTP)
++ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on));
+
+ return TRUE;
+ }
+@@ -1308,8 +1337,24 @@ ReadN(RTMP *r, char *buffer, int n)
+ return 0;
+ }
+ }
+- if (r->m_resplen && !r->m_sb.sb_size)
+- RTMPSockBuf_Fill(&r->m_sb);
++
++ // Try to fill the whole buffer. previous buffer needs to be consumed
++ // completely before receiving new data.
++ if (r->m_resplen && (r->m_sb.sb_size <= 0))
++ {
++ do
++ {
++ nBytes = RTMPSockBuf_Fill(&r->m_sb);
++ if (nBytes == -1)
++ {
++ if (!r->m_sb.sb_timedout)
++ RTMP_Close(r);
++ return 0;
++ }
++ }
++ while (r->m_resplen && (r->m_sb.sb_size < r->m_resplen) && (nBytes > 0));
++ }
++
+ avail = r->m_sb.sb_size;
+ if (avail > r->m_resplen)
+ avail = r->m_resplen;
+@@ -1336,10 +1381,9 @@ ReadN(RTMP *r, char *buffer, int n)
+ r->m_sb.sb_size -= nRead;
+ nBytes = nRead;
+ r->m_nBytesIn += nRead;
+- if (r->m_bSendCounter
+- && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
+- if (!SendBytesReceived(r))
+- return FALSE;
++ if (r->m_bSendCounter && r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10))
++ if (!SendBytesReceived(r))
++ return FALSE;
+ }
+ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
+ #ifdef _DEBUG
+@@ -1390,6 +1434,16 @@ WriteN(RTMP *r, const char *buffer, int n)
+ }
+ #endif
+
++ if (r->Link.ConnectPacket)
++ {
++ char *ConnectPacket = malloc(r->Link.HandshakeResponse.av_len + n);
++ memcpy(ConnectPacket, r->Link.HandshakeResponse.av_val, r->Link.HandshakeResponse.av_len);
++ memcpy(ConnectPacket + r->Link.HandshakeResponse.av_len, ptr, n);
++ ptr = ConnectPacket;
++ n += r->Link.HandshakeResponse.av_len;
++ r->Link.ConnectPacket = FALSE;
++ }
++
+ while (n > 0)
+ {
+ int nBytes;
+@@ -1455,6 +1509,9 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp)
+ char pbuf[4096], *pend = pbuf + sizeof(pbuf);
+ char *enc;
+
++ if (r->Link.CombineConnectPacket)
++ r->Link.ConnectPacket = TRUE;
++
+ if (cp)
+ return RTMP_SendPacket(r, cp, TRUE);
+
+@@ -1667,7 +1724,7 @@ SendUsherToken(RTMP *r, AVal *usherToken)
+ packet.m_hasAbsTimestamp = 0;
+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+- RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
++ RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %.*s", usherToken->av_len, usherToken->av_val);
+ enc = packet.m_body;
+ enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
+@@ -2096,10 +2153,8 @@ SendPlay(RTMP *r)
+ enc = AMF_EncodeNumber(enc, pend, -1000.0);
+ else
+ {
+- if (r->Link.seekTime > 0.0)
+- enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
+- else
+- enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */
++ if (r->Link.seekTime > 0.0 || r->Link.stopTime)
++ enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
+ }
+ if (!enc)
+ return FALSE;
+@@ -2215,7 +2270,7 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
+ int nSize;
+ char *buf;
+
+- RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
++ RTMP_Log(RTMP_LOGDEBUG, "sending ctrl, type: 0x%04x", (unsigned short)nType);
+
+ packet.m_nChannel = 0x02; /* control channel (ping) */
+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+@@ -2247,8 +2302,8 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
+ }
+ else if (nType == 0x1A)
+ {
+- *buf = nObject & 0xff;
+- }
++ *buf = nObject & 0xff;
++ }
+ else
+ {
+ if (nSize > 2)
+@@ -2305,6 +2360,7 @@ AV_clear(RTMP_METHOD *vals, int num)
+ free(vals);
+ }
+
++SAVC(onBWCheck);
+ SAVC(onBWDone);
+ SAVC(onFCSubscribe);
+ SAVC(onFCUnsubscribe);
+@@ -2314,24 +2370,26 @@ SAVC(_error);
+ SAVC(close);
+ SAVC(code);
+ SAVC(level);
++SAVC(description);
+ SAVC(onStatus);
+ SAVC(playlist_ready);
+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
+-static const AVal av_NetStream_Play_StreamNotFound =
+-AVC("NetStream.Play.StreamNotFound");
+-static const AVal av_NetConnection_Connect_InvalidApp =
+-AVC("NetConnection.Connect.InvalidApp");
++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound");
++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp");
+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
+ static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
+ static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
+-static const AVal av_NetStream_Play_PublishNotify =
+-AVC("NetStream.Play.PublishNotify");
+-static const AVal av_NetStream_Play_UnpublishNotify =
+-AVC("NetStream.Play.UnpublishNotify");
++static const AVal av_NetStream_Play_PublishNotify = AVC("NetStream.Play.PublishNotify");
++static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify");
+ static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
++static const AVal av_NetConnection_confStream = AVC("NetConnection.confStream");
++static const AVal av_verifyClient = AVC("verifyClient");
++static const AVal av_sendStatus = AVC("sendStatus");
++static const AVal av_getStreamLength = AVC("getStreamLength");
++static const AVal av_ReceiveCheckPublicStatus = AVC("ReceiveCheckPublicStatus");
+
+ /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
+ static int
+@@ -2341,6 +2399,11 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ AVal method;
+ double txn;
+ int ret = 0, nRes;
++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc, **params = NULL;
++ char *host = r->Link.hostname.av_len ? r->Link.hostname.av_val : "";
++ char *pageUrl = r->Link.pageUrl.av_len ? r->Link.pageUrl.av_val : "";
++ int param_count;
++ AVal av_Command, av_Response;
+ if (body[0] != 0x02) /* make sure it is a string method name we start with */
+ {
+ RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
+@@ -2402,23 +2465,137 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ RTMP_SendServerBW(r);
+ RTMP_SendCtrl(r, 3, 0, 300);
+ }
+- RTMP_SendCreateStream(r);
+-
+- if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
+- {
+- /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
+- if (r->Link.usherToken.av_len)
+- SendUsherToken(r, &r->Link.usherToken);
+- /* Send the FCSubscribe if live stream or if subscribepath is set */
+- if (r->Link.subscribepath.av_len)
+- SendFCSubscribe(r, &r->Link.subscribepath);
+- else if (r->Link.lFlags & RTMP_LF_LIVE)
+- SendFCSubscribe(r, &r->Link.playpath);
+- }
+- }
++ if (strstr(host, "tv-stream.to") || strstr(pageUrl, "tv-stream.to"))
++ {
++ static char auth[] = {'h', 0xC2, 0xA7, '4', 'j', 'h', 'H', '4', '3', 'd'};
++ AVal av_auth;
++ SAVC(requestAccess);
++ av_auth.av_val = auth;
++ av_auth.av_len = sizeof (auth);
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_requestAccess);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeString(enc, pend, &av_auth);
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++ SendInvoke(r, &av_Command, FALSE);
++
++ SAVC(getConnectionCount);
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_getConnectionCount);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++ SendInvoke(r, &av_Command, FALSE);
++
++ SendGetStreamLength(r);
++ }
++ else if (strstr(host, "jampo.com.ua") || strstr(pageUrl, "jampo.com.ua"))
++ {
++ SendGetStreamLength(r);
++ }
++ else if (strstr(host, "streamscene.cc") || strstr(pageUrl, "streamscene.cc")
++ || strstr(host, "tsboard.tv") || strstr(pageUrl, "teamstream.in"))
++ {
++ SAVC(r);
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_r);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++ SendInvoke(r, &av_Command, FALSE);
++
++ SendGetStreamLength(r);
++ }
++ else if (strstr(host, "chaturbate.com") || strstr(pageUrl, "chaturbate.com"))
++ {
++ AVal av_ModelName;
++ SAVC(CheckPublicStatus);
++
++ if (strlen(pageUrl) > 7)
++ {
++ strsplit(pageUrl + 7, FALSE, '/', ¶ms);
++ av_ModelName.av_val = params[1];
++ av_ModelName.av_len = strlen(params[1]);
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_CheckPublicStatus);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeString(enc, pend, &av_ModelName);
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++
++ SendInvoke(r, &av_Command, FALSE);
++ }
++ else
++ {
++ RTMP_Log(RTMP_LOGERROR, "you must specify the pageUrl");
++ RTMP_Close(r);
++ }
++ }
++ /* Weeb.tv specific authentication */
++ else if (r->Link.WeebToken.av_len)
++ {
++ AVal av_Token, av_Username, av_Password;
++ SAVC(determineAccess);
++
++ param_count = strsplit(r->Link.WeebToken.av_val, FALSE, ';', ¶ms);
++ if (param_count >= 1)
++ {
++ av_Token.av_val = params[0];
++ av_Token.av_len = strlen(params[0]);
++ }
++ if (param_count >= 2)
++ {
++ av_Username.av_val = params[1];
++ av_Username.av_len = strlen(params[1]);
++ }
++ if (param_count >= 3)
++ {
++ av_Password.av_val = params[2];
++ av_Password.av_len = strlen(params[2]);
++ }
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_determineAccess);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeString(enc, pend, &av_Token);
++ enc = AMF_EncodeString(enc, pend, &av_Username);
++ enc = AMF_EncodeString(enc, pend, &av_Password);
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++
++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", r->Link.WeebToken.av_val);
++ SendInvoke(r, &av_Command, FALSE);
++ }
++ else
++ RTMP_SendCreateStream(r);
++ }
++ else if (AVMATCH(&methodInvoked, &av_getStreamLength))
++ {
++ RTMP_SendCreateStream(r);
++ }
+ else if (AVMATCH(&methodInvoked, &av_createStream))
+- {
+- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
++ {
++ r->m_stream_id = (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
++
++ if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
++ {
++ /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
++ if (r->Link.usherToken.av_len)
++ SendUsherToken(r, &r->Link.usherToken);
++ /* Send the FCSubscribe if live stream or if subscribepath is set */
++ if (r->Link.subscribepath.av_len)
++ SendFCSubscribe(r, &r->Link.subscribepath);
++ else if ((r->Link.lFlags & RTMP_LF_LIVE) && (!r->Link.WeebToken.av_len))
++ SendFCSubscribe(r, &r->Link.playpath);
++ }
+
+ if (r->Link.protocol & RTMP_FEATURE_WRITE)
+ {
+@@ -2441,7 +2618,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ }
+ else if (AVMATCH(&method, &av_onBWDone))
+ {
+- if (!r->m_nBWCheckCounter)
++ if (!r->m_nBWCheckCounter)
+ SendCheckBW(r);
+ }
+ else if (AVMATCH(&method, &av_onFCSubscribe))
+@@ -2457,7 +2634,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ {
+ SendPong(r, txn);
+ }
+- else if (AVMATCH(&method, &av__onbwcheck))
++ else if (AVMATCH(&method, &av__onbwcheck) || AVMATCH(&method, &av_onBWCheck))
+ {
+ SendCheckBWResult(r, txn);
+ }
+@@ -2473,20 +2650,63 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ }
+ else if (AVMATCH(&method, &av__error))
+ {
+- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
++ double code = 0;
++ unsigned int parsedPort;
++ AMFObject obj2;
++ AMFObjectProperty p;
++ AVal redirect;
++ SAVC(ex);
++ SAVC(redirect);
++
++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_ex, &p))
++ {
++ AMFProp_GetObject(&p, &obj2);
++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_code, &p))
++ code = AMFProp_GetNumber(&p);
++ if (code == 302 && RTMP_FindFirstMatchingProperty(&obj2, &av_redirect, &p))
++ {
++ AMFProp_GetString(&p, &redirect);
++ r->Link.redirected = TRUE;
++
++ char *url = malloc(redirect.av_len + sizeof ("/playpath"));
++ strncpy(url, redirect.av_val, redirect.av_len);
++ url[redirect.av_len] = '\0';
++ r->Link.tcUrl.av_val = url;
++ r->Link.tcUrl.av_len = redirect.av_len;
++ strcat(url, "/playpath");
++ RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, &parsedPort, &r->Link.playpath0, &r->Link.app);
++ r->Link.port = parsedPort;
++ }
++ }
++ if (r->Link.redirected)
++ RTMP_Log(RTMP_LOGINFO, "rtmp server sent redirect");
++ else
++ RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+ }
+ else if (AVMATCH(&method, &av_close))
+ {
+- RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
+- RTMP_Close(r);
++ if (r->Link.redirected)
++ {
++ RTMP_Log(RTMP_LOGINFO, "trying to connect with redirected url");
++ RTMP_Close(r);
++ r->Link.redirected = FALSE;
++ RTMP_Connect(r, NULL);
++ }
++ else
++ {
++ RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
++ RTMP_Close(r);
++ }
+ }
+ else if (AVMATCH(&method, &av_onStatus))
+ {
+ AMFObject obj2;
+- AVal code, level;
++ AVal code, level, description;
+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
+ AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
++ AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
+
+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
+ if (AVMATCH(&code, &av_NetStream_Failed)
+@@ -2550,6 +2770,45 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ r->m_pausing = 3;
+ }
+ }
++
++ else if (AVMATCH(&code, &av_NetConnection_confStream))
++ {
++#ifdef CRYPTO
++ static const char hexdig[] = "0123456789abcdef";
++ SAVC(cf_stream);
++ int i;
++ char hash_hex[33] = {0};
++ unsigned char hash[16];
++ AVal auth;
++ param_count = strsplit(description.av_val, description.av_len, ':', ¶ms);
++ if (param_count >= 3)
++ {
++ char *buf = malloc(strlen(params[0]) + r->Link.playpath.av_len + 1);
++ strcpy(buf, params[0]);
++ strncat(buf, r->Link.playpath.av_val, r->Link.playpath.av_len);
++ md5_hash((unsigned char *) buf, strlen(buf), hash);
++ for (i = 0; i < 16; i++)
++ {
++ hash_hex[i * 2] = hexdig[0x0f & (hash[i] >> 4)];
++ hash_hex[i * 2 + 1] = hexdig[0x0f & (hash[i])];
++ }
++ auth.av_val = &hash_hex[atoi(params[1]) - 1];
++ auth.av_len = atoi(params[2]);
++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %.*s", auth.av_len, auth.av_val);
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_cf_stream);
++ enc = AMF_EncodeNumber(enc, pend, txn);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeString(enc, pend, &auth);
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++
++ SendInvoke(r, &av_Command, FALSE);
++ free(buf);
++ }
++#endif
++ }
+ }
+ else if (AVMATCH(&method, &av_playlist_ready))
+ {
+@@ -2563,6 +2822,74 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
+ }
+ }
+ }
++ else if (AVMATCH(&method, &av_verifyClient))
++ {
++ double VerificationNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
++ RTMP_Log(RTMP_LOGDEBUG, "VerificationNumber: %.2f", VerificationNumber);
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av__result);
++ enc = AMF_EncodeNumber(enc, pend, txn);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeNumber(enc, pend, exp(atan(sqrt(VerificationNumber))) + 1);
++ av_Response.av_val = pbuf;
++ av_Response.av_len = enc - pbuf;
++
++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE);
++ AMF_Dump(&obj);
++ SendInvoke(r, &av_Response, FALSE);
++ }
++ else if (AVMATCH(&method, &av_sendStatus))
++ {
++ if (r->Link.WeebToken.av_len)
++ {
++ AVal av_Authorized = AVC("User.hasAccess");
++ AVal av_TransferLimit = AVC("User.noPremium.limited");
++ AVal av_UserLimit = AVC("User.noPremium.tooManyUsers");
++ AVal av_TimeLeft = AVC("timeLeft");
++ AVal av_Status, av_ReconnectionTime;
++
++ AMFObject Status;
++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &Status);
++ AMFProp_GetString(AMF_GetProp(&Status, &av_code, -1), &av_Status);
++ RTMP_Log(RTMP_LOGINFO, "%.*s", av_Status.av_len, av_Status.av_val);
++ if (AVMATCH(&av_Status, &av_Authorized))
++ {
++ RTMP_Log(RTMP_LOGINFO, "Weeb.tv authentication successful");
++ RTMP_SendCreateStream(r);
++ }
++ else if (AVMATCH(&av_Status, &av_UserLimit))
++ {
++ RTMP_Log(RTMP_LOGINFO, "No free slots available");
++ RTMP_Close(r);
++ }
++ else if (AVMATCH(&av_Status, &av_TransferLimit))
++ {
++ AMFProp_GetString(AMF_GetProp(&Status, &av_TimeLeft, -1), &av_ReconnectionTime);
++ RTMP_Log(RTMP_LOGINFO, "Viewing limit exceeded. try again in %.*s minutes.", av_ReconnectionTime.av_len, av_ReconnectionTime.av_val);
++ RTMP_Close(r);
++ }
++ }
++ }
++ else if (AVMATCH(&method, &av_ReceiveCheckPublicStatus))
++ {
++ AVal Status;
++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &Status);
++ strsplit(Status.av_val, Status.av_len, ',', ¶ms);
++ if (strcmp(params[0], "0") == 0)
++ {
++ RTMP_Log(RTMP_LOGINFO, "Model status is %s", params[1]);
++ RTMP_Close(r);
++ }
++ else
++ {
++ AVal Playpath;
++ Playpath.av_val = params[1];
++ Playpath.av_len = strlen(params[1]);
++ RTMP_ParsePlaypath(&Playpath, &r->Link.playpath);
++ RTMP_SendCreateStream(r);
++ }
++ }
+ else
+ {
+
+@@ -2748,7 +3075,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet)
+ unsigned int tmp;
+ if (packet->m_body && packet->m_nBodySize >= 2)
+ nType = AMF_DecodeInt16(packet->m_body);
+- RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
++ RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl, type: %d, len: %d", __FUNCTION__, nType,
+ packet->m_nBodySize);
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+@@ -2856,15 +3183,15 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet)
+ RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
+ if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
+ {
+- RTMP_Log(RTMP_LOGERROR,
+- "%s: SWFVerification Type %d request not supported! Patches welcome...",
+- __FUNCTION__, packet->m_body[2]);
++ RTMP_Log(RTMP_LOGERROR,
++ "%s: SWFVerification Type %d request not supported, attempting to use SWFVerification Type 1! Patches welcome...",
++ __FUNCTION__, packet->m_body[2]);
+ }
+ #ifdef CRYPTO
+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
+
+ /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
+- else if (r->Link.SWFSize)
++ if (r->Link.SWFSize)
+ {
+ RTMP_SendCtrl(r, 0x1B, 0, 0);
+ }
+@@ -3142,8 +3469,18 @@ HandShake(RTMP *r, int FP9HandShake)
+ serversig[4], serversig[5], serversig[6], serversig[7]);
+
+ /* 2nd part of handshake */
+- if (!WriteN(r, serversig, RTMP_SIG_SIZE))
+- return FALSE;
++ if (r->Link.CombineConnectPacket)
++ {
++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE);
++ memcpy(HandshakeResponse, (char *) serversig, RTMP_SIG_SIZE);
++ r->Link.HandshakeResponse.av_val = HandshakeResponse;
++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE;
++ }
++ else
++ {
++ if (!WriteN(r, (char *) serversig, RTMP_SIG_SIZE))
++ return FALSE;
++ }
+
+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
+ return FALSE;
+@@ -3709,12 +4046,11 @@ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
+ char hbuf[512];
+ int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
+ "Host: %.*s:%d\r\n"
+- "Accept: */*\r\n"
+- "User-Agent: Shockwave Flash\n"
+- "Connection: Keep-Alive\n"
++ "User-Agent: Shockwave Flash\r\n"
++ "Connection: Keep-Alive\r\n"
+ "Cache-Control: no-cache\r\n"
+- "Content-type: application/x-fcs\r\n"
+- "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
++ "Content-Type: application/x-fcs\r\n"
++ "Content-Length: %d\r\n\r\n", RTMPT_cmds[cmd],
+ r->m_clientID.av_val ? r->m_clientID.av_val : "",
+ r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
+ r->Link.port, len);
+@@ -3749,6 +4085,14 @@ HTTP_read(RTMP *r, int fill)
+ if (!ptr)
+ return -1;
+ ptr += 4;
++ int resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start);
++ if (hlen < 4096)
++ while (resplen < hlen)
++ {
++ if (RTMPSockBuf_Fill(&r->m_sb) == -1)
++ return -1;
++ resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start);
++ }
+ r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
+ r->m_sb.sb_start = ptr;
+ r->m_unackd--;
+@@ -4301,13 +4645,21 @@ fail:
+ r->m_read.status = nRead;
+ goto fail;
+ }
+- /* buffer overflow, fix buffer and give up */
+- if (r->m_read.buf < mybuf || r->m_read.buf > end) {
+- mybuf = realloc(mybuf, cnt + nRead);
+- memcpy(mybuf+cnt, r->m_read.buf, nRead);
+- r->m_read.buf = mybuf+cnt+nRead;
+- break;
+- }
++ /* buffer overflow, fix buffer and give up */
++ if (r->m_read.buf < mybuf || r->m_read.buf > end)
++ {
++ if (!cnt)
++ {
++ mybuf = realloc(mybuf, sizeof (flvHeader) + cnt + nRead);
++ memcpy(mybuf, flvHeader, sizeof (flvHeader));
++ cnt += sizeof (flvHeader);
++ }
++ else
++ mybuf = realloc(mybuf, cnt + nRead);
++ memcpy(mybuf + cnt, r->m_read.buf, nRead);
++ r->m_read.buf = mybuf + cnt + nRead;
++ break;
++ }
+ cnt += nRead;
+ r->m_read.buf += nRead;
+ r->m_read.buflen -= nRead;
+@@ -4458,3 +4810,90 @@ RTMP_Write(RTMP *r, const char *buf, int size)
+ }
+ return size+s2;
+ }
++
++static int
++SendInvoke(RTMP *r, AVal *Command, int queue)
++{
++ RTMPPacket packet;
++ char pbuf[512], *enc;
++
++ packet.m_nChannel = 0x03; /* control channel (invoke) */
++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
++ packet.m_nTimeStamp = 0;
++ packet.m_nInfoField2 = 0;
++ packet.m_hasAbsTimestamp = 0;
++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
++
++ enc = packet.m_body;
++ if (Command->av_len)
++ {
++ memcpy(enc, Command->av_val, Command->av_len);
++ enc += Command->av_len;
++ }
++ else
++ return FALSE;
++ packet.m_nBodySize = enc - packet.m_body;
++
++ return RTMP_SendPacket(r, &packet, queue);
++}
++
++static int
++strsplit(char *src, int srclen, char delim, char ***params)
++{
++ char *sptr, *srcbeg, *srcend, *dstr;
++ int count = 1, i = 0, len = 0;
++
++ if (src == NULL)
++ return 0;
++ if (!srclen)
++ srclen = strlen(src);
++ srcbeg = src;
++ srcend = srcbeg + srclen;
++ sptr = srcbeg;
++
++ /* count the delimiters */
++ while (sptr < srcend)
++ {
++ if (*sptr++ == delim)
++ count++;
++ }
++ sptr = srcbeg;
++ *params = calloc(count, sizeof (size_t));
++ char **param = *params;
++
++ for (i = 0; i < (count - 1); i++)
++ {
++ dstr = strchr(sptr, delim);
++ len = dstr - sptr;
++ param[i] = calloc(len + 1, sizeof (char));
++ strncpy(param[i], sptr, len);
++ sptr += len + 1;
++ }
++
++ /* copy the last string */
++ if (sptr <= srcend)
++ {
++ len = srclen - (sptr - srcbeg);
++ param[i] = calloc(len + 1, sizeof (char));
++ strncpy(param[i], sptr, len);
++ }
++ return count;
++}
++
++static int
++SendGetStreamLength(RTMP *r)
++{
++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc;
++ AVal av_Command;
++
++ enc = pbuf;
++ enc = AMF_EncodeString(enc, pend, &av_getStreamLength);
++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
++ av_Command.av_val = pbuf;
++ av_Command.av_len = enc - pbuf;
++
++ return SendInvoke(r, &av_Command, TRUE);
++}
+diff --git a/librtmp/rtmp.h b/librtmp/rtmp.h
+index 6b2ae5b..411b488 100644
+--- a/librtmp/rtmp.h
++++ b/librtmp/rtmp.h
+@@ -150,12 +150,14 @@ extern "C"
+ AVal playpath; /* passed in explicitly */
+ AVal tcUrl;
+ AVal swfUrl;
++ AVal swfHash;
+ AVal pageUrl;
+ AVal app;
+ AVal auth;
+ AVal flashVer;
+ AVal subscribepath;
+ AVal usherToken;
++ AVal WeebToken;
+ AVal token;
+ AMFObject extras;
+ int edepth;
+@@ -172,9 +174,15 @@ extern "C"
+ int lFlags;
+
+ int swfAge;
++ int swfSize;
+
+ int protocol;
++ int ConnectPacket;
++ int CombineConnectPacket;
++ int redirected;
+ int timeout; /* connection timeout in seconds */
++ AVal Extras;
++ AVal HandshakeResponse;
+
+ unsigned short socksport;
+ unsigned short port;
+@@ -299,6 +307,7 @@ extern "C"
+ AVal *flashVer,
+ AVal *subscribepath,
+ AVal *usherToken,
++ AVal *WeebToken,
+ int dStart,
+ int dStop, int bLiveStream, long int timeout);
+
+diff --git a/librtmp/rtmp_sys.h b/librtmp/rtmp_sys.h
+index c3fd4a6..1bfb562 100644
+--- a/librtmp/rtmp_sys.h
++++ b/librtmp/rtmp_sys.h
+@@ -64,6 +64,7 @@
+ #include
+ #include
+ #include
++#include
+ typedef struct tls_ctx {
+ havege_state hs;
+ ssl_session ssn;
+@@ -71,7 +72,7 @@ typedef struct tls_ctx {
+ #define TLS_CTX tls_ctx *
+ #define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\
+ ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\
+- ssl_set_rng(s, havege_rand, &ctx->hs);\
++ ssl_set_rng(s, havege_random, &ctx->hs);\
+ ssl_set_ciphersuites(s, ssl_default_ciphersuites);\
+ ssl_set_session(s, 1, 600, &ctx->ssn)
+ #define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd)
+@@ -80,6 +81,7 @@ typedef struct tls_ctx {
+ #define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l)
+ #define TLS_shutdown(s) ssl_close_notify(s)
+ #define TLS_close(s) ssl_free(s); free(s)
++#define md5_hash(i, ilen, o) md5(i, ilen, o)
+
+ #elif defined(USE_GNUTLS)
+ #include
+@@ -95,6 +97,8 @@ typedef struct tls_ctx {
+ #define TLS_write(s,b,l) gnutls_record_send(s,b,l)
+ #define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR)
+ #define TLS_close(s) gnutls_deinit(s)
++#define md5_hash(i, ilen, o) gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_MD5;\
++ gnutls_hash_fast(algorithm, i, ilen, o);
+
+ #else /* USE_OPENSSL */
+ #define TLS_CTX SSL_CTX *
+@@ -105,6 +109,7 @@ typedef struct tls_ctx {
+ #define TLS_write(s,b,l) SSL_write(s,b,l)
+ #define TLS_shutdown(s) SSL_shutdown(s)
+ #define TLS_close(s) SSL_free(s)
++#define md5_hash(i, ilen, o) MD5(i, ilen, o)
+
+ #endif
+ #endif
+diff --git a/rtmpdump.c b/rtmpdump.c
+index e52f7d4..7bb0890 100644
+--- a/rtmpdump.c
++++ b/rtmpdump.c
+@@ -701,6 +701,8 @@ void usage(char *prog)
+ RTMP_LogPrintf
+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n");
+ RTMP_LogPrintf
++ ("--weeb|-J string Authentication token for weeb.tv servers\n");
++ RTMP_LogPrintf
+ ("--hashes|-# Display progress with hashes, not with the byte counter\n");
+ RTMP_LogPrintf
+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n",
+@@ -747,7 +749,8 @@ main(int argc, char **argv)
+ AVal hostname = { 0, 0 };
+ AVal playpath = { 0, 0 };
+ AVal subscribepath = { 0, 0 };
+- AVal usherToken = { 0, 0 }; //Justin.tv auth token
++ AVal usherToken = { 0, 0 }; // Justin.tv auth token
++ AVal WeebToken = { 0, 0 }; // Weeb.tv auth token
+ int port = -1;
+ int protocol = RTMP_PROTOCOL_UNDEFINED;
+ int retries = 0;
+@@ -852,12 +855,13 @@ main(int argc, char **argv)
+ {"quiet", 0, NULL, 'q'},
+ {"verbose", 0, NULL, 'V'},
+ {"jtv", 1, NULL, 'j'},
++ {"weeb", 1, NULL, 'J'},
+ {0, 0, 0, 0}
+ };
+
+ while ((opt =
+ getopt_long(argc, argv,
+- "hVveqzRr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:",
++ "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:J:",
+ longopts, NULL)) != -1)
+ {
+ switch (opt)
+@@ -1070,6 +1074,9 @@ main(int argc, char **argv)
+ case 'j':
+ STR2AVAL(usherToken, optarg);
+ break;
++ case 'J':
++ STR2AVAL(WeebToken, optarg);
++ break;
+ default:
+ RTMP_LogPrintf("unknown option: %c\n", opt);
+ usage(argv[0]);
+@@ -1161,14 +1168,14 @@ main(int argc, char **argv)
+
+ if (tcUrl.av_len == 0)
+ {
+- tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
+- hostname.av_len + app.av_len + sizeof("://:65535/");
++ tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
++ hostname.av_len + app.av_len + sizeof ("://:65535/");
+ tcUrl.av_val = (char *) malloc(tcUrl.av_len);
+- if (!tcUrl.av_val)
+- return RD_FAILED;
++ if (!tcUrl.av_val)
++ return RD_FAILED;
+ tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s",
+- RTMPProtocolStringsLower[protocol], hostname.av_len,
+- hostname.av_val, port, app.av_len, app.av_val);
++ RTMPProtocolStringsLower[protocol], hostname.av_len,
++ hostname.av_val, port, app.av_len, app.av_val);
+ }
+
+ int first = 1;
+@@ -1187,7 +1194,7 @@ main(int argc, char **argv)
+
+ RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
+ &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
+- &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);
++ &flashVer, &subscribepath, &usherToken, &WeebToken, dSeek, dStopOffset, bLiveStream, timeout);
+
+ /* Try to keep the stream moving if it pauses on us */
+ if (!bLiveStream && !bRealtimeStream && !(protocol & RTMP_FEATURE_HTTP))
+diff --git a/rtmpgw.c b/rtmpgw.c
+index 0cf56bb..cd4396d 100644
+--- a/rtmpgw.c
++++ b/rtmpgw.c
+@@ -95,7 +95,8 @@ typedef struct
+ AVal flashVer;
+ AVal token;
+ AVal subscribepath;
+- AVal usherToken; //Justin.tv auth token
++ AVal usherToken; // Justin.tv auth token
++ AVal WeebToken; // Weeb.tv auth token
+ AVal sockshost;
+ AMFObject extras;
+ int edepth;
+@@ -553,7 +554,7 @@ void processTCPrequest(STREAMING_SERVER * server, // server socket and state (ou
+ RTMP_Init(&rtmp);
+ RTMP_SetBufferMS(&rtmp, req.bufferTime);
+ RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost,
+- &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, dSeek, req.dStopOffset,
++ &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, &req.WeebToken, dSeek, req.dStopOffset,
+ req.bLiveStream, req.timeout);
+ /* backward compatibility, we always sent this as true before */
+ if (req.auth.av_len)
+@@ -957,6 +958,9 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req)
+ case 'j':
+ STR2AVAL(req->usherToken, arg);
+ break;
++ case 'J':
++ STR2AVAL(req->WeebToken, arg);
++ break;
+ default:
+ RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg);
+ return FALSE;
+@@ -1028,6 +1032,7 @@ main(int argc, char **argv)
+ {"quiet", 0, NULL, 'q'},
+ {"verbose", 0, NULL, 'V'},
+ {"jtv", 1, NULL, 'j'},
++ {"weeb", 1, NULL, 'J'},
+ {0, 0, 0, 0}
+ };
+
+@@ -1040,7 +1045,7 @@ main(int argc, char **argv)
+
+ while ((opt =
+ getopt_long(argc, argv,
+- "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:", longopts,
++ "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:J:", longopts,
+ NULL)) != -1)
+ {
+ switch (opt)
+@@ -1103,6 +1108,8 @@ main(int argc, char **argv)
+ RTMP_LogPrintf
+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n");
+ RTMP_LogPrintf
++ ("--weeb|-J string Authentication token for weeb.tv servers\n");
++ RTMP_LogPrintf
+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n\n",
+ defaultRTMPRequest.bufferTime);
+
+diff --git a/rtmpsrv.c b/rtmpsrv.c
+index 9aa62f3..9ec8f23 100644
+--- a/rtmpsrv.c
++++ b/rtmpsrv.c
+@@ -96,9 +96,20 @@ STREAMING_SERVER *rtmpServer = 0; // server structure pointer
+ STREAMING_SERVER *startStreaming(const char *address, int port);
+ void stopStreaming(STREAMING_SERVER * server);
+ void AVreplace(AVal *src, const AVal *orig, const AVal *repl);
++char *strreplace(char *srcstr, int srclen, char *orig, char *repl);
++int file_exists(const char *fname);
++int SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit);
++AVal AVcopy(AVal src);
++AVal StripParams(AVal *src);
+
+ static const AVal av_dquote = AVC("\"");
+ static const AVal av_escdquote = AVC("\\\"");
++#ifdef WIN32
++static const AVal av_caret = AVC("^");
++static const AVal av_esccaret = AVC("^^");
++static const AVal av_pipe = AVC("|");
++static const AVal av_escpipe = AVC("^|");
++#endif
+
+ typedef struct
+ {
+@@ -167,6 +178,10 @@ SAVC(level);
+ SAVC(code);
+ SAVC(description);
+ SAVC(secureToken);
++SAVC(_checkbw);
++SAVC(_onbwdone);
++SAVC(checkBandwidth);
++SAVC(onBWDone);
+
+ static int
+ SendConnectResult(RTMP *r, double txn)
+@@ -190,7 +205,7 @@ SendConnectResult(RTMP *r, double txn)
+ enc = AMF_EncodeNumber(enc, pend, txn);
+ *enc++ = AMF_OBJECT;
+
+- STR2AVAL(av, "FMS/3,5,1,525");
++ STR2AVAL(av, "FMS/3,5,7,7009");
+ enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av);
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0);
+ enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0);
+@@ -212,7 +227,7 @@ SendConnectResult(RTMP *r, double txn)
+ enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av);
+ #endif
+ STR2AVAL(p.p_name, "version");
+- STR2AVAL(p.p_vu.p_aval, "3,5,1,525");
++ STR2AVAL(p.p_vu.p_aval, "3,5,7,7009");
+ p.p_type = AMF_STRING;
+ obj.o_num = 1;
+ obj.o_props = &p;
+@@ -268,7 +283,7 @@ static int
+ SendPlayStart(RTMP *r)
+ {
+ RTMPPacket packet;
+- char pbuf[512], *pend = pbuf+sizeof(pbuf);
++ char pbuf[1024], *pend = pbuf + sizeof (pbuf);
+
+ packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
+@@ -300,7 +315,7 @@ static int
+ SendPlayStop(RTMP *r)
+ {
+ RTMPPacket packet;
+- char pbuf[512], *pend = pbuf+sizeof(pbuf);
++ char pbuf[1024], *pend = pbuf + sizeof (pbuf);
+
+ packet.m_nChannel = 0x03; // control channel (invoke)
+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
+@@ -328,6 +343,49 @@ SendPlayStop(RTMP *r)
+ return RTMP_SendPacket(r, &packet, FALSE);
+ }
+
++int
++SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit)
++{
++ RTMPPacket packet;
++ char pbuf[256], *pend = pbuf + sizeof (pbuf);
++ char *enc;
++
++ packet.m_nChannel = 0x03; /* control channel (invoke) */
++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
++ packet.m_nTimeStamp = 0;
++ packet.m_nInfoField2 = 0;
++ packet.m_hasAbsTimestamp = 0;
++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
++
++ enc = packet.m_body;
++ if (oldMethodType)
++ {
++ enc = AMF_EncodeString(enc, pend, &av__onbwdone);
++ enc = AMF_EncodeNumber(enc, pend, 0);
++ *enc++ = AMF_NULL;
++ enc = AMF_EncodeNumber(enc, pend, 10240);
++ enc = AMF_EncodeNumber(enc, pend, 10240);
++ }
++ else
++ {
++ enc = AMF_EncodeString(enc, pend, &av_onBWDone);
++ enc = AMF_EncodeNumber(enc, pend, 0);
++ *enc++ = AMF_NULL;
++ if (!onBWDoneInit)
++ {
++ enc = AMF_EncodeNumber(enc, pend, 10240);
++ enc = AMF_EncodeNumber(enc, pend, 10240);
++ enc = AMF_EncodeNumber(enc, pend, 0);
++ enc = AMF_EncodeNumber(enc, pend, 0);
++ }
++ }
++
++ packet.m_nBodySize = enc - packet.m_body;
++
++ return RTMP_SendPacket(r, &packet, FALSE);
++}
++
+ static void
+ spawn_dumper(int argc, AVal *av, char *cmd)
+ {
+@@ -568,6 +626,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ server->arglen += countAMF(&r->Link.extras, &server->argc);
+ }
+ SendConnectResult(r, txn);
++ SendCheckBWResponse(r, FALSE, TRUE);
+ }
+ else if (AVMATCH(&method, &av_createStream))
+ {
+@@ -582,10 +641,22 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ AVal usherToken;
+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken);
+ AVreplace(&usherToken, &av_dquote, &av_escdquote);
++#ifdef WIN32
++ AVreplace(&usherToken, &av_caret, &av_esccaret);
++ AVreplace(&usherToken, &av_pipe, &av_escpipe);
++#endif
+ server->arglen += 6 + usherToken.av_len;
+ server->argc += 2;
+ r->Link.usherToken = usherToken;
+ }
++ else if (AVMATCH(&method, &av__checkbw))
++ {
++ SendCheckBWResponse(r, TRUE, FALSE);
++ }
++ else if (AVMATCH(&method, &av_checkBandwidth))
++ {
++ SendCheckBWResponse(r, FALSE, FALSE);
++ }
+ else if (AVMATCH(&method, &av_play))
+ {
+ char *file, *p, *q, *cmd, *ptr;
+@@ -599,6 +670,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ if (obj.o_num > 5)
+ r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5));
+ */
++ double StartFlag = 0;
++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4);
++ if (!(Start->p_type == AMF_INVALID))
++ StartFlag = AMFProp_GetNumber(Start);
++ r->Link.app = AVcopy(r->Link.app);
++ if (StartFlag == -1000 || strstr(r->Link.app.av_val, "live"))
++ {
++ StartFlag = -1000;
++ server->arglen += 7;
++ server->argc += 1;
++ }
+ if (r->Link.tcUrl.av_len)
+ {
+ len = server->arglen + r->Link.playpath.av_len + 4 +
+@@ -616,6 +698,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ argv[argc].av_val = ptr + 1;
+ argv[argc++].av_len = 2;
+ argv[argc].av_val = ptr + 5;
++ r->Link.tcUrl = StripParams(&r->Link.tcUrl);
+ ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val);
+ argv[argc++].av_len = r->Link.tcUrl.av_len;
+
+@@ -640,6 +723,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ argv[argc].av_val = ptr + 1;
+ argv[argc++].av_len = 2;
+ argv[argc].av_val = ptr + 5;
++ r->Link.swfUrl = StripParams(&r->Link.swfUrl);
+ ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val);
+ argv[argc++].av_len = r->Link.swfUrl.av_len;
+ }
+@@ -662,10 +746,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ r->Link.usherToken.av_val = NULL;
+ r->Link.usherToken.av_len = 0;
+ }
+- if (r->Link.extras.o_num) {
+- ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc);
+- AMF_Reset(&r->Link.extras);
+- }
++ if (StartFlag == -1000)
++ {
++ argv[argc].av_val = ptr + 1;
++ argv[argc++].av_len = 6;
++ ptr += sprintf(ptr, " --live");
++ }
++ if (r->Link.extras.o_num)
++ {
++ ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc);
++ AMF_Reset(&r->Link.extras);
++ }
+ argv[argc].av_val = ptr + 1;
+ argv[argc++].av_len = 2;
+ argv[argc].av_val = ptr + 5;
+@@ -673,7 +764,13 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ r->Link.playpath.av_len, r->Link.playpath.av_val);
+ argv[argc++].av_len = r->Link.playpath.av_len;
+
+- av = r->Link.playpath;
++ if (r->Link.playpath.av_len)
++ av = r->Link.playpath;
++ else
++ {
++ av.av_val = "file";
++ av.av_len = 4;
++ }
+ /* strip trailing URL parameters */
+ q = memchr(av.av_val, '?', av.av_len);
+ if (q)
+@@ -725,7 +822,30 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ argv[argc++].av_len = 2;
+ argv[argc].av_val = file;
+ argv[argc].av_len = av.av_len;
+- ptr += sprintf(ptr, " -o %s", file);
++#ifdef VLC
++ char *vlc;
++ int didAlloc = FALSE;
++
++ if (getenv("VLC"))
++ vlc = getenv("VLC");
++ else if (getenv("ProgramFiles"))
++ {
++ vlc = malloc(512 * sizeof (char));
++ didAlloc = TRUE;
++ char *ProgramFiles = getenv("ProgramFiles");
++ sprintf(vlc, "%s%s", ProgramFiles, " (x86)\\VideoLAN\\VLC\\vlc.exe");
++ if (!file_exists(vlc))
++ sprintf(vlc, "%s%s", ProgramFiles, "\\VideoLAN\\VLC\\vlc.exe");
++ }
++ else
++ vlc = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe";
++
++ ptr += sprintf(ptr, " | %s -", vlc);
++ if (didAlloc)
++ free(vlc);
++#else
++ ptr += sprintf(ptr, " -o %s", file);
++#endif
+ now = RTMP_GetTime();
+ if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename))
+ {
+@@ -739,7 +859,23 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
+ server->filetime = now;
+ free(server->filename.av_val);
+ server->filename = argv[argc++];
+- spawn_dumper(argc, argv, cmd);
++#ifdef VLC
++ FILE *vlc_cmdfile = fopen("VLC.bat", "w");
++ char *vlc_batchcmd = strreplace(cmd, 0, "%", "%%");
++ fprintf(vlc_cmdfile, "%s\n", vlc_batchcmd);
++ fclose(vlc_cmdfile);
++ free(vlc_batchcmd);
++ spawn_dumper(argc, argv, "VLC.bat");
++#else
++ spawn_dumper(argc, argv, cmd);
++#endif
++
++#ifdef WIN32
++ // Dump command to batch file
++ FILE *cmdfile = fopen("Command.bat", "a");
++ fprintf(cmdfile, "%s\n", cmd);
++ fclose(cmdfile);
++#endif
+ }
+
+ free(cmd);
+@@ -1178,3 +1314,115 @@ AVreplace(AVal *src, const AVal *orig, const AVal *repl)
+ src->av_val = dest;
+ src->av_len = dptr - dest;
+ }
++
++char *
++strreplace(char *srcstr, int srclen, char *orig, char *repl)
++{
++ char *ptr = NULL, *sptr = srcstr;
++ int origlen = strlen(orig);
++ int repllen = strlen(repl);
++ if (!srclen)
++ srclen = strlen(srcstr);
++ char *srcend = srcstr + srclen;
++ int dstbuffer = srclen / origlen * repllen;
++ if (dstbuffer < srclen)
++ dstbuffer = srclen;
++ char *dststr = calloc(dstbuffer + 1, sizeof (char));
++ char *dptr = dststr;
++
++ if ((ptr = strstr(srcstr, orig)))
++ {
++ while (ptr < srcend && (ptr = strstr(sptr, orig)))
++ {
++ int len = ptr - sptr;
++ memcpy(dptr, sptr, len);
++ sptr += len + origlen;
++ dptr += len;
++ memcpy(dptr, repl, repllen);
++ dptr += repllen;
++ }
++ memcpy(dptr, sptr, srcend - sptr);
++ return dststr;
++ }
++
++ memcpy(dststr, srcstr, srclen);
++ return dststr;
++}
++
++AVal
++StripParams(AVal *src)
++{
++ AVal str;
++ if (src->av_val)
++ {
++ str.av_val = calloc(src->av_len + 1, sizeof (char));
++ strncpy(str.av_val, src->av_val, src->av_len);
++ str.av_len = src->av_len;
++ char *start = str.av_val;
++ char *end = start + str.av_len;
++ char *ptr = start;
++
++ while (ptr < end)
++ {
++ if (*ptr == '?')
++ {
++ str.av_len = ptr - start;
++ break;
++ }
++ ptr++;
++ }
++ memset(start + str.av_len, 0, 1);
++
++ char *dynamic = strstr(start, "[[DYNAMIC]]");
++ if (dynamic)
++ {
++ dynamic -= 1;
++ memset(dynamic, 0, 1);
++ str.av_len = dynamic - start;
++ end = start + str.av_len;
++ }
++
++ char *import = strstr(start, "[[IMPORT]]");
++ if (import)
++ {
++ str.av_val = import + 11;
++ strcpy(start, "http://");
++ str.av_val = strcat(start, str.av_val);
++ str.av_len = strlen(str.av_val);
++ }
++ return str;
++ }
++ str = *src;
++ return str;
++}
++
++int
++file_exists(const char *fname)
++{
++ FILE *file;
++ if ((file = fopen(fname, "r")))
++ {
++ fclose(file);
++ return TRUE;
++ }
++ return FALSE;
++}
++
++AVal
++AVcopy(AVal src)
++{
++ AVal dst;
++ if (src.av_len)
++ {
++ dst.av_val = malloc(src.av_len + 1);
++ memcpy(dst.av_val, src.av_val, src.av_len);
++ dst.av_val[src.av_len] = '\0';
++ dst.av_len = src.av_len;
++ }
++ else
++ {
++ dst.av_val = NULL;
++ dst.av_len = 0;
++ }
++ return dst;
++}
+diff --git a/rtmpsuck.c b/rtmpsuck.c
+index e886179..e80c686 100644
+--- a/rtmpsuck.c
++++ b/rtmpsuck.c
+@@ -143,15 +143,18 @@ SAVC(onStatus);
+ SAVC(close);
+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
+-static const AVal av_NetStream_Play_StreamNotFound =
+-AVC("NetStream.Play.StreamNotFound");
+-static const AVal av_NetConnection_Connect_InvalidApp =
+-AVC("NetConnection.Connect.InvalidApp");
++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound");
++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp");
+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
++static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
+
+ static const char *cst[] = { "client", "server" };
++char *dumpAMF(AMFObject *obj, char *ptr);
++char *strreplace(char *srcstr, int srclen, char *orig, char *repl);
++AVal AVcopy(AVal src);
++AVal StripParams(AVal *src);
+
+ // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete'
+ int
+@@ -198,26 +201,28 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ if (cobj.o_props[i].p_type == AMF_STRING)
+ {
+ pval = cobj.o_props[i].p_vu.p_aval;
+- RTMP_LogPrintf("%.*s: %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val);
++ RTMP_LogPrintf("%10.*s : %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val);
+ }
+ if (AVMATCH(&pname, &av_app))
+ {
+- server->rc.Link.app = pval;
++ server->rc.Link.app = AVcopy(pval);
+ pval.av_val = NULL;
+ }
+ else if (AVMATCH(&pname, &av_flashVer))
+ {
+- server->rc.Link.flashVer = pval;
++ server->rc.Link.flashVer = AVcopy(pval);
+ pval.av_val = NULL;
+ }
+ else if (AVMATCH(&pname, &av_swfUrl))
+ {
+ #ifdef CRYPTO
+ if (pval.av_val)
+- RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize,
+- (unsigned char *)server->rc.Link.SWFHash, 30);
++ {
++ AVal swfUrl = StripParams(&pval);
++ RTMP_HashSWF(swfUrl.av_val, &server->rc.Link.SWFSize, (unsigned char *) server->rc.Link.SWFHash, 30);
++ }
+ #endif
+- server->rc.Link.swfUrl = pval;
++ server->rc.Link.swfUrl = AVcopy(pval);
+ pval.av_val = NULL;
+ }
+ else if (AVMATCH(&pname, &av_tcUrl))
+@@ -225,7 +230,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ char *r1 = NULL, *r2;
+ int len;
+
+- server->rc.Link.tcUrl = pval;
++ server->rc.Link.tcUrl = AVcopy(pval);
+ if ((pval.av_val[0] | 0x40) == 'r' &&
+ (pval.av_val[1] | 0x40) == 't' &&
+ (pval.av_val[2] | 0x40) == 'm' &&
+@@ -267,7 +272,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ }
+ else if (AVMATCH(&pname, &av_pageUrl))
+ {
+- server->rc.Link.pageUrl = pval;
++ server->rc.Link.pageUrl = AVcopy(pval);
+ pval.av_val = NULL;
+ }
+ else if (AVMATCH(&pname, &av_audioCodecs))
+@@ -287,14 +292,21 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ if (pval.av_val)
+ free(pval.av_val);
+ }
++
+ if (obj.o_num > 3)
+ {
+- if (AMFProp_GetBoolean(&obj.o_props[3]))
+- server->rc.Link.lFlags |= RTMP_LF_AUTH;
+- if (obj.o_num > 4)
+- {
+- AMFProp_GetString(&obj.o_props[4], &server->rc.Link.auth);
+- }
++ int i = obj.o_num - 3;
++ server->rc.Link.extras.o_num = i;
++ server->rc.Link.extras.o_props = malloc(i * sizeof (AMFObjectProperty));
++ memcpy(server->rc.Link.extras.o_props, obj.o_props + 3, i * sizeof (AMFObjectProperty));
++ obj.o_num = 3;
++ }
++
++ if (server->rc.Link.extras.o_num)
++ {
++ server->rc.Link.Extras.av_val = calloc(1024, sizeof (char));
++ dumpAMF(&server->rc.Link.extras, server->rc.Link.Extras.av_val);
++ server->rc.Link.Extras.av_len = strlen(server->rc.Link.Extras.av_val);
+ }
+
+ if (!RTMP_Connect(&server->rc, pack))
+@@ -303,6 +315,16 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ return 1;
+ }
+ server->rc.m_bSendCounter = FALSE;
++
++ if (server->rc.Link.extras.o_props)
++ {
++ AMF_Reset(&server->rc.Link.extras);
++ }
++ }
++ else if (AVMATCH(&method, &av_NetStream_Authenticate_UsherToken))
++ {
++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &server->rc.Link.usherToken);
++ RTMP_LogPrintf("%10s : %.*s\n", "usherToken", server->rc.Link.usherToken.av_len, server->rc.Link.usherToken.av_val);
+ }
+ else if (AVMATCH(&method, &av_play))
+ {
+@@ -323,6 +345,14 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ if (!av.av_val)
+ goto out;
+
++ double StartFlag = 0;
++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4);
++ if (!(Start->p_type == AMF_INVALID))
++ StartFlag = AMFProp_GetNumber(Start);
++ if (StartFlag == -1000 || strstr(server->rc.Link.app.av_val, "live"))
++ StartFlag = -1000;
++ RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag == -1000) ? "yes" : "no");
++
+ /* check for duplicates */
+ for (fl = server->f_head; fl; fl=fl->f_next)
+ {
+@@ -372,9 +402,51 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
+ for (p=file; *p; p++)
+ if (*p == ':')
+ *p = '_';
+- RTMP_LogPrintf("Playpath: %.*s\nSaving as: %s\n",
+- server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val,
+- file);
++ RTMP_LogPrintf("%10s : %.*s\n%10s : %s\n", "Playpath", server->rc.Link.playpath.av_len,
++ server->rc.Link.playpath.av_val, "Saving as", file);
++
++#ifdef WIN32
++ // Dump command to batch file
++ char *cmd = NULL, *ptr = NULL;
++ AVal swfUrl, tcUrl;
++
++ cmd = calloc(2048, sizeof (char));
++ ptr = cmd;
++ tcUrl = StripParams(&server->rc.Link.tcUrl);
++ swfUrl = StripParams(&server->rc.Link.swfUrl);
++ ptr += sprintf(ptr, "rtmpdump -r \"%.*s\" -a \"%.*s\" -f \"%.*s\" -W \"%.*s\" -p \"%.*s\"",
++ tcUrl.av_len, tcUrl.av_val,
++ server->rc.Link.app.av_len, server->rc.Link.app.av_val,
++ server->rc.Link.flashVer.av_len, server->rc.Link.flashVer.av_val,
++ swfUrl.av_len, swfUrl.av_val,
++ server->rc.Link.pageUrl.av_len, server->rc.Link.pageUrl.av_val);
++
++ if (server->rc.Link.usherToken.av_val)
++ {
++ char *usherToken = strreplace(server->rc.Link.usherToken.av_val, server->rc.Link.usherToken.av_len, "\"", "\\\"");
++ usherToken = strreplace(usherToken, 0, "^", "^^");
++ usherToken = strreplace(usherToken, 0, "|", "^|");
++ ptr += sprintf(ptr, " --jtv \"%s\"", usherToken);
++ free(usherToken);
++ }
++
++ if (server->rc.Link.Extras.av_len)
++ {
++ ptr += sprintf(ptr, "%.*s", server->rc.Link.Extras.av_len, server->rc.Link.Extras.av_val);
++ }
++
++ if (StartFlag == -1000)
++ ptr += sprintf(ptr, "%s", " --live");
++ ptr += sprintf(ptr, " -y \"%.*s\"", server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val);
++ ptr += sprintf(ptr, " -o \"%s.flv\"\n", file);
++
++ FILE *cmdfile = fopen("Command.bat", "a");
++ fprintf(cmdfile, "%s", cmd);
++ fclose(cmdfile);
++
++ free(cmd);
++#endif
++
+ out = fopen(file, "wb");
+ free(file);
+ if (!out)
+@@ -1196,3 +1268,146 @@ main(int argc, char **argv)
+ #endif
+ return nStatus;
+ }
++
++char *
++dumpAMF(AMFObject *obj, char *ptr)
++{
++ int i;
++ const char opt[] = "NBSO Z";
++
++ for (i = 0; i < obj->o_num; i++)
++ {
++ AMFObjectProperty *p = &obj->o_props[i];
++ if (p->p_type > 5)
++ continue;
++ ptr += sprintf(ptr, " -C ");
++ if (p->p_name.av_val)
++ *ptr++ = 'N';
++ *ptr++ = opt[p->p_type];
++ *ptr++ = ':';
++ if (p->p_name.av_val)
++ ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val);
++ switch (p->p_type)
++ {
++ case AMF_BOOLEAN:
++ *ptr++ = p->p_vu.p_number != 0 ? '1' : '0';
++ break;
++ case AMF_STRING:
++ memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len);
++ ptr += p->p_vu.p_aval.av_len;
++ break;
++ case AMF_NUMBER:
++ ptr += sprintf(ptr, "%f", p->p_vu.p_number);
++ break;
++ case AMF_OBJECT:
++ *ptr++ = '1';
++ ptr = dumpAMF(&p->p_vu.p_object, ptr);
++ ptr += sprintf(ptr, " -C O:0");
++ break;
++ case AMF_NULL:
++ default:
++ break;
++ }
++ }
++ return ptr;
++}
++
++char *
++strreplace(char *srcstr, int srclen, char *orig, char *repl)
++{
++ char *ptr = NULL, *sptr = srcstr;
++ int origlen = strlen(orig);
++ int repllen = strlen(repl);
++ if (!srclen)
++ srclen = strlen(srcstr);
++ char *srcend = srcstr + srclen;
++ int dstbuffer = srclen / origlen * repllen;
++ if (dstbuffer < srclen)
++ dstbuffer = srclen;
++ char *dststr = calloc(dstbuffer + 1, sizeof (char));
++ char *dptr = dststr;
++
++ if ((ptr = strstr(srcstr, orig)))
++ {
++ while (ptr < srcend && (ptr = strstr(sptr, orig)))
++ {
++ int len = ptr - sptr;
++ memcpy(dptr, sptr, len);
++ sptr += len + origlen;
++ dptr += len;
++ memcpy(dptr, repl, repllen);
++ dptr += repllen;
++ }
++ memcpy(dptr, sptr, srcend - sptr);
++ return dststr;
++ }
++
++ memcpy(dststr, srcstr, srclen);
++ return dststr;
++}
++
++AVal
++StripParams(AVal *src)
++{
++ AVal str;
++ if (src->av_val)
++ {
++ str.av_val = calloc(src->av_len + 1, sizeof (char));
++ strncpy(str.av_val, src->av_val, src->av_len);
++ str.av_len = src->av_len;
++ char *start = str.av_val;
++ char *end = start + str.av_len;
++ char *ptr = start;
++
++ while (ptr < end)
++ {
++ if (*ptr == '?')
++ {
++ str.av_len = ptr - start;
++ break;
++ }
++ ptr++;
++ }
++ memset(start + str.av_len, 0, 1);
++
++ char *dynamic = strstr(start, "[[DYNAMIC]]");
++ if (dynamic)
++ {
++ dynamic -= 1;
++ memset(dynamic, 0, 1);
++ str.av_len = dynamic - start;
++ end = start + str.av_len;
++ }
++
++ char *import = strstr(start, "[[IMPORT]]");
++ if (import)
++ {
++ str.av_val = import + 11;
++ strcpy(start, "http://");
++ str.av_val = strcat(start, str.av_val);
++ str.av_len = strlen(str.av_val);
++ }
++ return str;
++ }
++ str = *src;
++ return str;
++}
++
++AVal
++AVcopy(AVal src)
++{
++ AVal dst;
++ if (src.av_len)
++ {
++ dst.av_val = malloc(src.av_len + 1);
++ memcpy(dst.av_val, src.av_val, src.av_len);
++ dst.av_val[src.av_len] = '\0';
++ dst.av_len = src.av_len;
++ }
++ else
++ {
++ dst.av_val = NULL;
++ dst.av_len = 0;
++ }
++ return dst;
++}
diff --git a/tools/android/depends/libssh/android.patch b/tools/android/depends/libssh/android.patch
index c76e648f7f31c..b2fc58d11b080 100644
--- a/tools/android/depends/libssh/android.patch
+++ b/tools/android/depends/libssh/android.patch
@@ -1,49 +1,61 @@
---- src/connect.c 2011-05-31 10:29:52.000000000 -0400
-+++ src/connect.c 2012-07-25 23:15:22.281514489 -0400
+--- src/connect.c 2011-05-31 10:29:52.000000000 -0400
++++ src/connect.c 2012-07-25 23:15:22.281514489 -0400
@@ -159,7 +159,7 @@
int timeout_ms;
ssh_pollfd_t fds;
int rc = 0;
- unsigned int len = sizeof(rc);
+ socklen_t len = sizeof(rc);
-
+
enter_function();
---- src/misc.c 2011-05-31 10:29:52.000000000 -0400
-+++ src/misc.c 2012-07-25 23:24:46.611514133 -0400
-@@ -207,6 +207,9 @@
- #endif /* NSS_BUFLEN_PASSWD */
+--- src/misc.c 2012-10-08 23:50:23.567426941 -0400
++++ src/misc.c 2012-10-09 00:19:57.217425822 -0400
+@@ -208,17 +208,12 @@
char *ssh_get_user_home_dir(void) {
-+#if defined(__ANDROID__)
-+ return NULL;
-+#else
char *szPath = NULL;
- struct passwd pwd;
- struct passwd *pwdbuf;
-@@ -221,6 +224,7 @@
- szPath = strdup(pwd.pw_dir);
+- struct passwd pwd;
+- struct passwd *pwdbuf;
+- char buf[NSS_BUFLEN_PASSWD];
+- int rc;
+-
+- rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
+- if (rc != 0) {
++ struct passwd *pwd = NULL;
++ pwd = getpwuid(getuid());
++ if ( pwd == NULL)
+ return NULL;
+- }
+
+- szPath = strdup(pwd.pw_dir);
++ szPath = strdup(pwd->pw_dir);
return szPath;
-+#endif
}
-
- /* we have read access on file */
-@@ -233,6 +237,9 @@
+@@ -233,20 +228,16 @@
}
char *ssh_get_local_username(ssh_session session) {
-+#if defined(__ANDROID__)
-+ return NULL;
-+#else
- struct passwd pwd;
- struct passwd *pwdbuf;
- char buf[NSS_BUFLEN_PASSWD];
-@@ -254,6 +261,7 @@
+- struct passwd pwd;
+- struct passwd *pwdbuf;
+- char buf[NSS_BUFLEN_PASSWD];
+- char *name;
+- int rc;
+-
+- rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
+- if (rc != 0) {
++ char *name = NULL;
++ struct passwd *pwd = NULL;
++ pwd = getpwuid(getuid());
++ if ( pwd == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "Couldn't retrieve information for current user!");
+ return NULL;
}
- return name;
-+#endif
- }
+- name = strdup(pwd.pw_name);
++ name = strdup(pwd->pw_name);
- int ssh_is_ipaddr_v4(const char *str) {
+ if (name == NULL) {
+ ssh_set_error_oom(session);
diff --git a/tools/android/depends/xbmc/Makefile b/tools/android/depends/xbmc/Makefile
index a5c5c3207b36f..986b19855143b 100644
--- a/tools/android/depends/xbmc/Makefile
+++ b/tools/android/depends/xbmc/Makefile
@@ -20,7 +20,8 @@ CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) build-aux/ ;\
--enable-neon --enable-gles --enable-debug \
--disable-sdl --disable-x11 --disable-xrandr \
--disable-optical-drive --disable-joystick \
- --enable-shared-lib --disable-alsa
+ --enable-shared-lib --disable-alsa \
+ --enable-codec=amcodec --enable-player=amlplayer
all: $(SOURCE)/libxbmc.so
diff --git a/tools/android/packaging/Makefile b/tools/android/packaging/Makefile
index 124be50dc2021..72d01244fc42c 100644
--- a/tools/android/packaging/Makefile
+++ b/tools/android/packaging/Makefile
@@ -5,7 +5,7 @@ OBJS = libcurl.so \
libafpclient.so \
libshairport.so libplist.so \
libxbogg.so libxbvorbis.so libxbvorbisfile.so libxbFLAC.so libxbmpeg2.so \
- libxbmpeg2convert.so libnfs.so
+ libxbmpeg2convert.so libnfs.so libass.so
PLATFORM_OBJS =
EXCLUDED_ADDONS = screensaver.rsxs.euphoria visualization.dxspectrum visualization.milkdrop visualization.projectm
@@ -65,6 +65,7 @@ extras: libs
cd xbmc/assets/python2.6/lib/python2.6/; rm -rf test config lib-dynload
mkdir -p tmp/res; $(AAPT) c -S xbmc/res -C tmp/res; cp -r -n xbmc/res tmp/ || true
$(AAPT) p -f -I $(SDKROOT)/platforms/$(SDK_PLATFORM)/android.jar -S tmp/res/ -M xbmc/AndroidManifest.xml -F images/xbmcapp-debug-skeleton.apk -J xbmc/src
+ test -d config && cp -f config/* xbmc/assets/system
@rm -rf tmp/
libs: $(PREFIX)/lib/xbmc/libxbmc.so
diff --git a/tools/android/packaging/config/advancedsettings.xml b/tools/android/packaging/config/advancedsettings.xml
new file mode 100644
index 0000000000000..f9270929277ce
--- /dev/null
+++ b/tools/android/packaging/config/advancedsettings.xml
@@ -0,0 +1,25 @@
+
+
+ lookandfeel.soundskin
+ videoplayer.rendermethod
+ videoplayer.adjustrefreshrate
+ videoplayer.pauseafterrefreshchange
+ videoplayer.usedisplayasclock
+ videoplayer.synctype
+ audiocds
+ karaoke
+ videoscreen.screenmode
+ videoscreen.screen
+ videoscreen.vsync
+ videoscreen.testpattern
+ audiooutput.mode
+ audiooutput.channellayout
+ audiooutput.audiodevice
+ audiooutput.customdevice
+ audiooutput.passthroughdevice
+ audiooutput.custompassthrough
+ input.remoteaskeyboard
+ audiooutput.guisoundmode
+
+
+
diff --git a/tools/android/packaging/config/guisettings.xml b/tools/android/packaging/config/guisettings.xml
new file mode 100644
index 0000000000000..1b71e6020c349
--- /dev/null
+++ b/tools/android/packaging/config/guisettings.xml
@@ -0,0 +1,20 @@
+
+
+ false
+
+
+ 0
+ false
+ false
+ false
+ false>
+ false
+ 2
+
+
+ 2
+
+
+ true
+
+
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index c6f0a14361e12..6367e1b77523f 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -18,7 +18,6 @@
*
*/
-#include "network/Network.h"
#include "threads/SystemClock.h"
#include "system.h"
#include "Application.h"
@@ -249,9 +248,7 @@
#include "pictures/GUIDialogPictureInfo.h"
#include "addons/GUIDialogAddonSettings.h"
#include "addons/GUIDialogAddonInfo.h"
-#ifdef HAS_LINUX_NETWORK
#include "network/GUIDialogAccessPoints.h"
-#endif
/* PVR related include Files */
#include "pvr/PVRManager.h"
@@ -335,6 +332,10 @@
#include "input/SDLJoystick.h"
#endif
+#if defined(TARGET_ANDROID)
+#include "android/activity/XBMCApp.h"
+#endif
+
using namespace std;
using namespace ADDON;
using namespace XFILE;
@@ -386,7 +387,6 @@ CApplication::CApplication(void)
, m_musicInfoScanner(new CMusicInfoScanner)
, m_seekHandler(new CSeekHandler)
{
- m_network = NULL;
TiXmlBase::SetCondenseWhiteSpace(false);
m_iPlaySpeed = 1;
m_bInhibitIdleShutdown = false;
@@ -567,14 +567,6 @@ void CApplication::Preflight()
bool CApplication::Create()
{
-#if defined(HAS_LINUX_NETWORK)
- m_network = new CNetworkLinux();
-#elif defined(HAS_WIN32_NETWORK)
- m_network = new CNetworkWin32();
-#else
- m_network = new CNetwork();
-#endif
-
Preflight();
g_settings.Initialize(); //Initialize default AdvancedSettings
@@ -647,7 +639,7 @@ bool CApplication::Create()
CStdString executable = CUtil::ResolveExecutablePath();
CLog::Log(LOGNOTICE, "The executable running is: %s", executable.c_str());
- CLog::Log(LOGNOTICE, "Local hostname: %s", m_network->GetHostName().c_str());
+ CLog::Log(LOGNOTICE, "Local hostname: %s", m_network.GetDefaultConnectionName().c_str());
CLog::Log(LOGNOTICE, "Log File is located: %sxbmc.log", g_settings.m_logFolder.c_str());
CLog::Log(LOGNOTICE, "-----------------------------------------------------------------------");
@@ -744,6 +736,8 @@ bool CApplication::Create()
CAEFactory::SetMute (g_settings.m_bMute);
CAEFactory::SetSoundMode(g_guiSettings.GetInt("audiooutput.guisoundmode"));
+ m_network.Initialize();
+
// initialize the addon database (must be before the addon manager is init'd)
CDatabaseManager::Get().Initialize(true);
@@ -754,6 +748,9 @@ bool CApplication::Create()
CLog::Log(LOGFATAL, "CApplication::Create: Unable to start CAddonMgr");
return false;
}
+#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
+ g_RemoteControl.Initialize();
+#endif
g_peripherals.Initialise();
@@ -763,9 +760,6 @@ bool CApplication::Create()
g_Mouse.SetEnabled(g_guiSettings.GetBool("input.enablemouse"));
g_Keyboard.Initialize();
-#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
- g_RemoteControl.Initialize();
-#endif
#if defined(TARGET_DARWIN_OSX)
// Configure and possible manually start the helper.
@@ -1280,10 +1274,8 @@ bool CApplication::Initialize()
g_windowManager.Add(new CGUIDialogBusy);
g_windowManager.Add(new CGUIDialogPictureInfo);
g_windowManager.Add(new CGUIDialogAddonInfo);
- g_windowManager.Add(new CGUIDialogAddonSettings);
-#ifdef HAS_LINUX_NETWORK
- g_windowManager.Add(new CGUIDialogAccessPoints);
-#endif
+ g_windowManager.Add(new CGUIDialogAddonSettings); // window id = 140
+ g_windowManager.Add(new CGUIDialogAccessPoints); // window id = 141
g_windowManager.Add(new CGUIDialogLockSettings);
@@ -1411,6 +1403,7 @@ bool CApplication::Initialize()
// reset our screensaver (starts timers etc.)
ResetScreenSaver();
+ m_keyringManager.Initialize();
#ifdef HAS_SDL_JOYSTICK
g_Joystick.SetEnabled(g_guiSettings.GetBool("input.enablejoystick") &&
@@ -1517,7 +1510,7 @@ bool CApplication::StartServer(enum ESERVERS eServer, bool bStart, bool bWait/*
bool CApplication::StartWebServer()
{
#ifdef HAS_WEB_SERVER
- if (g_guiSettings.GetBool("services.webserver") && m_network->IsAvailable())
+ if (g_guiSettings.GetBool("services.webserver") && m_network.IsAvailable())
{
int webPort = atoi(g_guiSettings.GetString("services.webserverport"));
CLog::Log(LOGNOTICE, "Webserver: Starting...");
@@ -1532,7 +1525,7 @@ bool CApplication::StartWebServer()
bool started = false;
if (m_WebServer.Start(webPort, g_guiSettings.GetString("services.webserverusername"), g_guiSettings.GetString("services.webserverpassword")))
{
- std::map txt;
+ std::vector > txt;
started = true;
// publish web frontend and API services
#ifdef HAS_WEB_INTERFACE
@@ -1573,7 +1566,7 @@ bool CApplication::StartAirplayServer()
{
bool ret = false;
#ifdef HAS_AIRPLAY
- if (g_guiSettings.GetBool("services.airplay") && m_network->IsAvailable())
+ if (g_guiSettings.GetBool("services.airplay") && m_network.IsAvailable())
{
int listenPort = g_advancedSettings.m_airPlayPort;
CStdString password = g_guiSettings.GetString("services.airplaypassword");
@@ -1582,19 +1575,16 @@ bool CApplication::StartAirplayServer()
if (CAirPlayServer::StartServer(listenPort, true))
{
CAirPlayServer::SetCredentials(usePassword, password);
- std::map txt;
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface)
- {
- txt["deviceid"] = iface->GetMacAddress();
- }
- else
- {
- txt["deviceid"] = "FF:FF:FF:FF:FF:F2";
- }
- txt["features"] = "0x77";
- txt["model"] = "AppleTV2,1";
- txt["srcvers"] = AIRPLAY_SERVER_VERSION_STR;
+ std::vector > txt;
+
+ std::string mac_address(m_network.GetDefaultConnectionMacAddress());
+ if (mac_address.empty())
+ mac_address = "FF:FF:FF:FF:FF:F2";
+ txt.push_back(std::make_pair("deviceid", mac_address));
+ txt.push_back(std::make_pair("features", "0x77"));
+ txt.push_back(std::make_pair("model", "Xbmc,1"));
+ txt.push_back(std::make_pair("srcvers", AIRPLAY_SERVER_VERSION_STR));
+
CZeroconf::GetInstance()->PublishService("servers.airplay", "_airplay._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), listenPort, txt);
ret = true;
}
@@ -1603,7 +1593,7 @@ bool CApplication::StartAirplayServer()
#endif
{
#ifdef HAS_AIRTUNES
- if (g_guiSettings.GetBool("services.airplay") && m_network->IsAvailable())
+ if (g_guiSettings.GetBool("services.airplay") && m_network.IsAvailable())
{
int listenPort = g_advancedSettings.m_airTunesPort;
CStdString password = g_guiSettings.GetString("services.airplaypassword");
@@ -1638,7 +1628,7 @@ bool CApplication::StartJSONRPCServer()
{
if (CTCPServer::StartServer(g_advancedSettings.m_jsonTcpPort, g_guiSettings.GetBool("services.esallinterfaces")))
{
- std::map txt;
+ std::vector > txt;
CZeroconf::GetInstance()->PublishService("servers.jsonrpc-tpc", "_xbmc-jsonrpc._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), g_advancedSettings.m_jsonTcpPort, txt);
return true;
}
@@ -1866,8 +1856,6 @@ void CApplication::StartServices()
void CApplication::StopServices()
{
- m_network->NetworkMessage(CNetwork::SERVICES_DOWN, 0);
-
#if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
CLog::Log(LOGNOTICE, "stop dvd detect media");
m_DetectDVDType.StopThread();
@@ -2280,7 +2268,7 @@ void CApplication::Render()
bool extPlayerActive = m_eCurrentPlayer == EPC_EXTPLAYER && IsPlaying() && !m_AppFocused;
m_bPresentFrame = false;
- if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused())
+ if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused() && g_renderManager.RendererHandlesPresent())
{
CSingleLock lock(m_frameMutex);
@@ -2291,6 +2279,12 @@ void CApplication::Render()
decrement = m_bPresentFrame;
hasRendered = true;
}
+ else if(!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !g_renderManager.RendererHandlesPresent())
+ {
+ //Whether we're paused or not, if the renderer isn't in charge of presenting and we're fullscreen, we limit
+ singleFrameTime = 30;
+ limitFrames = true;
+ }
else
{
// engage the frame limiter as needed
@@ -2859,15 +2853,19 @@ bool CApplication::OnAction(const CAction &action)
if (g_settings.m_bMute)
UnMute();
float volume = g_settings.m_fVolumeLevel;
+// Android has steps based on the max available volume level
+#if defined(TARGET_ANDROID)
+ float step = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / CXBMCApp::GetMaxSystemVolume();
+#else
float step = (VOLUME_MAXIMUM - VOLUME_MINIMUM) / VOLUME_CONTROL_STEPS;
+
if (action.GetRepeat())
step *= action.GetRepeat() * 50; // 50 fps
-
+#endif
if (action.GetID() == ACTION_VOLUME_UP)
volume += (float)fabs(action.GetAmount()) * action.GetAmount() * step;
else
volume -= (float)fabs(action.GetAmount()) * action.GetAmount() * step;
-
SetVolume(volume, false);
}
// show visual feedback of volume change...
@@ -3484,9 +3482,6 @@ bool CApplication::Cleanup()
while(1); // execution ends
#endif
- delete m_network;
- m_network = NULL;
-
return true;
}
catch (...)
@@ -3622,6 +3617,8 @@ void CApplication::Stop(int exitCode)
}
#endif
+ m_network.StopServices();
+
g_Windowing.DestroyRenderSystem();
g_Windowing.DestroyWindow();
g_Windowing.DestroyWindowSystem();
@@ -5113,6 +5110,7 @@ void CApplication::Process()
void CApplication::ProcessSlow()
{
g_powerManager.ProcessEvents();
+ m_network.PumpNetworkEvents();
#if defined(TARGET_DARWIN_OSX)
// There is an issue on OS X that several system services ask the cursor to become visible
@@ -5886,9 +5884,14 @@ void CApplication::SetRenderGUI(bool renderGUI)
m_renderGUI = renderGUI;
}
-CNetwork& CApplication::getNetwork()
+CNetworkManager& CApplication::getNetworkManager()
{
- return *m_network;
+ return m_network;
+}
+
+CKeyringManager& CApplication::getKeyringManager()
+{
+ return m_keyringManager;
}
#ifdef HAS_PERFORMANCE_SAMPLE
CPerformanceStats &CApplication::GetPerformanceStats()
@@ -5896,4 +5899,3 @@ CPerformanceStats &CApplication::GetPerformanceStats()
return m_perfStats;
}
#endif
-
diff --git a/xbmc/Application.h b/xbmc/Application.h
index 69609fae744d1..3fbb499e54128 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -53,6 +53,8 @@ namespace MEDIA_DETECT
#ifdef _WIN32
#include "win32/WIN32Util.h"
#endif
+#include "network/NetworkManager.h"
+#include "security/KeyringManager.h"
#include "utils/Stopwatch.h"
#include "utils/CharsetConverter.h"
#ifdef HAS_PERFORMANCE_SAMPLE
@@ -265,7 +267,10 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
static bool OnEvent(XBMC_Event& newEvent);
- CNetwork& getNetwork();
+ CNetworkManager& getNetworkManager();
+
+ CKeyringManager& getKeyringManager();
+
#ifdef HAS_PERFORMANCE_SAMPLE
CPerformanceStats &GetPerformanceStats();
#endif
@@ -460,7 +465,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
CSeekHandler *m_seekHandler;
CInertialScrollingHandler *m_pInertialScrollingHandler;
- CNetwork *m_network;
+ CNetworkManager m_network;
+ CKeyringManager m_keyringManager;
#ifdef HAS_PERFORMANCE_SAMPLE
CPerformanceStats m_perfStats;
#endif
diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp
index 59c2ee23e33e5..724073436dd83 100644
--- a/xbmc/ApplicationMessenger.cpp
+++ b/xbmc/ApplicationMessenger.cpp
@@ -29,7 +29,6 @@
#endif
#include "pictures/GUIWindowSlideShow.h"
#include "interfaces/Builtins.h"
-#include "network/Network.h"
#include "utils/log.h"
#include "utils/URIUtils.h"
#include "utils/Variant.h"
@@ -646,7 +645,7 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case TMSG_NETWORKMESSAGE:
{
- g_application.getNetwork().NetworkMessage((CNetwork::EMESSAGE)pMsg->dwParam1, (int)pMsg->dwParam2);
+ g_application.getNetworkManager().NetworkMessage((CNetworkManager::EMESSAGE)pMsg->dwParam1, (int)pMsg->dwParam2);
}
break;
diff --git a/xbmc/DynamicDll.h b/xbmc/DynamicDll.h
index 8a4972783b9be..739250f867f20 100644
--- a/xbmc/DynamicDll.h
+++ b/xbmc/DynamicDll.h
@@ -1,5 +1,4 @@
#pragma once
-
/*
* Copyright (C) 2005-2012 Team XBMC
* http://www.xbmc.org
@@ -356,12 +355,10 @@ public: \
#define BEGIN_METHOD_RESOLVE() \
protected: \
virtual bool ResolveExports() \
- { \
- return (
+ {
#define END_METHOD_RESOLVE() \
- 1 \
- ); \
+ return true; \
}
///////////////////////////////////////////////////////////
@@ -374,10 +371,33 @@ public: \
// or DEFINE_METHOD_LINKAGE
//
#define RESOLVE_METHOD(method) \
- m_dll->ResolveExport( #method , & m_##method##_ptr ) &&
+ if (!m_dll->ResolveExport( #method , & m_##method##_ptr )) \
+ return false;
#define RESOLVE_METHOD_FP(method) \
- m_dll->ResolveExport( #method , & method##_ptr ) &&
+ if (!m_dll->ResolveExport( #method , & method##_ptr )) \
+ return false;
+
+
+///////////////////////////////////////////////////////////
+//
+// RESOLVE_METHOD_OPTIONAL
+//
+// Resolves a method from a dll. does not abort if the
+// method is missing
+//
+// method: Name of the method defined with DEFINE_METHOD
+// or DEFINE_METHOD_LINKAGE
+//
+
+#define RESOLVE_METHOD_OPTIONAL(method) \
+ m_dll->ResolveExport( #method , & m_##method##_ptr );
+
+#define RESOLVE_METHOD_OPTIONAL_FP(method) \
+ method##_ptr = NULL; \
+ m_dll->ResolveExport( #method , & method##_ptr );
+
+
///////////////////////////////////////////////////////////
//
@@ -390,10 +410,12 @@ public: \
// or DEFINE_METHOD_LINKAGE
//
#define RESOLVE_METHOD_RENAME(dllmethod, method) \
- m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) &&
+ if (!m_dll->ResolveExport( #dllmethod , & m_##method##_ptr )) \
+ return false;
#define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
- m_dll->ResolveExport( #dllmethod , & method##_ptr ) &&
+ if (!m_dll->ResolveExport( #dllmethod , & method##_ptr )) \
+ return false;
////////////////////////////////////////////////////////////////////
diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp
index a4098e00f3d2b..e50194174f3a9 100644
--- a/xbmc/GUIInfoManager.cpp
+++ b/xbmc/GUIInfoManager.cpp
@@ -18,7 +18,6 @@
*
*/
-#include "network/Network.h"
#include "system.h"
#include "GUIInfoManager.h"
#include "windows/GUIMediaWindow.h"
@@ -1513,7 +1512,6 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
break;
case SYSTEM_VIDEO_ENCODER_INFO:
- case NETWORK_MAC_ADDRESS:
case SYSTEM_KERNEL_VERSION:
case SYSTEM_CPUFREQUENCY:
case SYSTEM_INTERNET_STATE:
@@ -1712,7 +1710,7 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
{
CStdString friendlyName = g_guiSettings.GetString("services.devicename");
if (friendlyName.Equals("XBMC"))
- strLabel.Format("%s (%s)", friendlyName.c_str(), g_application.getNetwork().GetHostName().c_str());
+ strLabel.Format("%s (%s)", friendlyName.c_str(), g_application.getNetworkManager().GetDefaultConnectionName().c_str());
else
strLabel = friendlyName;
}
@@ -1759,39 +1757,20 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
break;
#endif
case NETWORK_IP_ADDRESS:
- {
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface)
- return iface->GetCurrentIPAddress();
- }
+ return g_application.getNetworkManager().GetDefaultConnectionAddress();
break;
case NETWORK_SUBNET_MASK:
- {
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface)
- return iface->GetCurrentNetmask();
- }
+ return g_application.getNetworkManager().GetDefaultConnectionNetmask();
+ break;
+ case NETWORK_MAC_ADDRESS:
+ return g_application.getNetworkManager().GetDefaultConnectionMacAddress();
break;
case NETWORK_GATEWAY_ADDRESS:
- {
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface)
- return iface->GetCurrentDefaultGateway();
- }
+ return g_application.getNetworkManager().GetDefaultConnectionGateway();
break;
case NETWORK_DNS1_ADDRESS:
- {
- vector nss = g_application.getNetwork().GetNameServers();
- if (nss.size() >= 1)
- return nss[0];
- }
- break;
case NETWORK_DNS2_ADDRESS:
- {
- vector nss = g_application.getNetwork().GetNameServers();
- if (nss.size() >= 2)
- return nss[1];
- }
+ return g_application.getNetworkManager().GetDefaultConnectionNameServer();
break;
case NETWORK_DHCP_ADDRESS:
{
@@ -1803,8 +1782,7 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
{
CStdString linkStatus = g_localizeStrings.Get(151);
linkStatus += " ";
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface && iface->IsConnected())
+ if (g_application.getNetworkManager().IsConnected())
linkStatus += g_localizeStrings.Get(15207);
else
linkStatus += g_localizeStrings.Get(15208);
diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp
index 5071fe90d43bf..9d273e6247ed4 100644
--- a/xbmc/LangInfo.cpp
+++ b/xbmc/LangInfo.cpp
@@ -156,7 +156,7 @@ void CLangInfo::CRegion::SetGlobalLocale()
// decimal separator is changed depending of the current language
// (ie. "," in French or Dutch instead of "."). This breaks atof() and
// others similar functions.
-#if defined(__FreeBSD__) || defined(TARGET_DARWIN_OSX)
+#if defined(__FreeBSD__) || defined(TARGET_DARWIN_OSX) || defined(TARGET_LINUX)
// on FreeBSD and darwin libstdc++ is compiled with "generic" locale support
if (setlocale(LC_COLLATE, strLocale.c_str()) == NULL
|| setlocale(LC_CTYPE, strLocale.c_str()) == NULL)
diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp
index 241bc9a62e740..4385d0cf8f87c 100644
--- a/xbmc/Util.cpp
+++ b/xbmc/Util.cpp
@@ -17,7 +17,6 @@
* .
*
*/
-#include "network/Network.h"
#include "threads/SystemClock.h"
#include "system.h"
#if defined(TARGET_DARWIN)
@@ -1899,7 +1898,7 @@ void CUtil::ScanForExternalSubtitles(const CStdString& strMovie, std::vectorclazz;
+ jclass cActivity = env->GetObjectClass(oActivity);
+
+ // Get Audio manager
+ // (AudioManager)getSystemService(Context.AUDIO_SERVICE)
+ jmethodID mgetSystemService = env->GetMethodID(cActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
+ jstring sAudioService = env->NewStringUTF("audio");
+ jobject oAudioManager = env->CallObjectMethod(oActivity, mgetSystemService, sAudioService);
+ env->DeleteLocalRef(sAudioService);
+ env->DeleteLocalRef(cActivity);
+
+ // Get max volume
+ // int max_volume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ jclass cAudioManager = env->GetObjectClass(oAudioManager);
+ jmethodID mgetStreamMaxVolume = env->GetMethodID(cAudioManager, "getStreamMaxVolume", "(I)I");
+ jfieldID fstreamMusic = env->GetStaticFieldID(cAudioManager, "STREAM_MUSIC", "I");
+ jint stream_music = env->GetStaticIntField(cAudioManager, fstreamMusic);
+ int maxVolume = (int)env->CallObjectMethod(oAudioManager, mgetStreamMaxVolume, stream_music); // AudioManager.STREAM_MUSIC
+
+ env->DeleteLocalRef(oAudioManager);
+ env->DeleteLocalRef(cAudioManager);
+
+ return maxVolume;
+}
+
+void CXBMCApp::SetSystemVolume(JNIEnv *env, float percent)
+{
+ CLog::Log(LOGDEBUG, "CXBMCApp::SetSystemVolume: %f", percent);
+
+ jobject oActivity = m_activity->clazz;
+ jclass cActivity = env->GetObjectClass(oActivity);
+
+ // Get Audio manager
+ // (AudioManager)getSystemService(Context.AUDIO_SERVICE)
+ jmethodID mgetSystemService = env->GetMethodID(cActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
+ jstring sAudioService = env->NewStringUTF("audio");
+ jobject oAudioManager = env->CallObjectMethod(oActivity, mgetSystemService, sAudioService);
+ jclass cAudioManager = env->GetObjectClass(oAudioManager);
+ env->DeleteLocalRef(sAudioService);
+ env->DeleteLocalRef(cActivity);
+
+ // Set volume
+ // mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, max_volume, 0);
+ jfieldID fstreamMusic = env->GetStaticFieldID(cAudioManager, "STREAM_MUSIC", "I");
+ jint stream_music = env->GetStaticIntField(cAudioManager, fstreamMusic);
+ jmethodID msetStreamVolume = env->GetMethodID(cAudioManager, "setStreamVolume", "(III)V");
+ env->CallObjectMethod(oAudioManager, msetStreamVolume, stream_music, int(GetMaxSystemVolume(env)*percent), 0);
+ env->DeleteLocalRef(oAudioManager);
+ env->DeleteLocalRef(cAudioManager);
+}
+
diff --git a/xbmc/android/activity/XBMCApp.h b/xbmc/android/activity/XBMCApp.h
index 4bf2d2e6a5231..c620966db3cb7 100644
--- a/xbmc/android/activity/XBMCApp.h
+++ b/xbmc/android/activity/XBMCApp.h
@@ -87,6 +87,7 @@ class CXBMCApp : public IActivityHandler
static bool ListApplications(std::vector *applications);
static bool GetIconSize(const std::string &packageName, int *width, int *height);
static bool GetIcon(const std::string &packageName, void* buffer, unsigned int bufSize);
+
/*!
* \brief If external storage is available, it returns the path for the external storage (for the specified type)
* \param path will contain the path of the external storage (for the specified type)
@@ -95,6 +96,7 @@ class CXBMCApp : public IActivityHandler
*/
static bool GetExternalStorage(std::string &path, const std::string &type = "");
static bool GetStorageUsage(const std::string &path, std::string &usage);
+ static int GetMaxSystemVolume();
static int GetDPI();
protected:
@@ -106,6 +108,9 @@ class CXBMCApp : public IActivityHandler
static int AttachCurrentThread(JNIEnv** p_env, void* thr_args = NULL);
static int DetachCurrentThread();
+ static int GetMaxSystemVolume(JNIEnv *env);
+ static void SetSystemVolume(JNIEnv *env, float percent);
+
private:
static bool HasLaunchIntent(const std::string &package);
bool getWakeLock(JNIEnv *env);
@@ -116,7 +121,6 @@ class CXBMCApp : public IActivityHandler
static ANativeActivity *m_activity;
jobject m_wakeLock;
-
typedef enum {
// XBMC_Initialize hasn't been executed yet
Uninitialized,
diff --git a/xbmc/cores/AudioEngine/AEAudioFormat.h b/xbmc/cores/AudioEngine/AEAudioFormat.h
index 11d2d29dc5f2e..5a9053f9fe7a4 100644
--- a/xbmc/cores/AudioEngine/AEAudioFormat.h
+++ b/xbmc/cores/AudioEngine/AEAudioFormat.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp
index 86392c1fff01c..f0b4177901acf 100644
--- a/xbmc/cores/AudioEngine/AEFactory.cpp
+++ b/xbmc/cores/AudioEngine/AEFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h
index 3c296efa9e7b3..99cdebd10c354 100644
--- a/xbmc/cores/AudioEngine/AEFactory.h
+++ b/xbmc/cores/AudioEngine/AEFactory.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp
index b066ecd30e1a9..41e2298566c10 100644
--- a/xbmc/cores/AudioEngine/AESinkFactory.cpp
+++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -129,28 +129,28 @@ IAESink *CAESinkFactory::Create(std::string &device, AEAudioFormat &desiredForma
return NULL;
}
-#define ENUMERATE_SINK(SINK) { \
+#define ENUMERATE_SINK(SINK, force) { \
AESinkInfo info; \
info.m_sinkName = #SINK; \
- CAESink ##SINK::EnumerateDevicesEx(info.m_deviceInfoList); \
+ CAESink ##SINK::EnumerateDevicesEx(info.m_deviceInfoList, force); \
if(!info.m_deviceInfoList.empty()) \
list.push_back(info); \
}
-void CAESinkFactory::EnumerateEx(AESinkInfoList &list)
+void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
{
#if defined(TARGET_WINDOWS)
- ENUMERATE_SINK(DirectSound);
+ ENUMERATE_SINK(DirectSound, force);
if (g_sysinfo.IsVistaOrHigher() && !g_advancedSettings.m_audioForceDirectSound)
- ENUMERATE_SINK(WASAPI);
+ ENUMERATE_SINK(WASAPI, force);
#elif defined(TARGET_ANDROID)
- ENUMERATE_SINK(AUDIOTRACK);
+ ENUMERATE_SINK(AUDIOTRACK, force);
#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
#if defined(HAS_ALSA)
- ENUMERATE_SINK(ALSA);
+ ENUMERATE_SINK(ALSA, force);
#endif
- ENUMERATE_SINK(OSS);
+ ENUMERATE_SINK(OSS, force);
#endif
}
diff --git a/xbmc/cores/AudioEngine/AESinkFactory.h b/xbmc/cores/AudioEngine/AESinkFactory.h
index 99c53f9be2244..5444d2ca86e98 100644
--- a/xbmc/cores/AudioEngine/AESinkFactory.h
+++ b/xbmc/cores/AudioEngine/AESinkFactory.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -40,6 +40,6 @@ class CAESinkFactory
public:
static void ParseDevice(std::string &device, std::string &driver);
static IAESink *Create(std::string &device, AEAudioFormat &desiredFormat, bool rawPassthrough);
- static void EnumerateEx(AESinkInfoList &list);
+ static void EnumerateEx(AESinkInfoList &list, bool force = false); /* The force flag can be used to indicate the rescan devices */
};
diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
index 8ade469d6aa48..c611f15e8f5ac 100644
--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
+++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h
index b69f8c63a1ac5..0cedf3fa8c0af 100644
--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h
+++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
index 410e20ce41a4f..c28da7048be62 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -59,6 +59,7 @@ CSoftAE::CSoftAE():
m_audiophile (true ),
m_running (false ),
m_reOpen (false ),
+ m_sinkIsSuspended (false ),
m_isSuspended (false ),
m_softSuspend (false ),
m_softSuspendTimer (0 ),
@@ -74,21 +75,18 @@ CSoftAE::CSoftAE():
m_outputStageFn (NULL ),
m_streamStageFn (NULL )
{
+ unsigned int c_retry = 5;
CAESinkFactory::EnumerateEx(m_sinkInfoList);
- for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
+ while(m_sinkInfoList.size() == 0 && c_retry > 0)
{
- CLog::Log(LOGNOTICE, "Enumerated %s devices:", itt->m_sinkName.c_str());
- int count = 0;
- for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
- {
- CLog::Log(LOGNOTICE, " Device %d", ++count);
- CAEDeviceInfo& info = *itt2;
- std::stringstream ss((std::string)info);
- std::string line;
- while(std::getline(ss, line, '\n'))
- CLog::Log(LOGNOTICE, " %s", line.c_str());
- }
+ CLog::Log(LOGNOTICE, "No Devices found - retry: %d", c_retry);
+ Sleep(2000);
+ c_retry--;
+ // retry the enumeration
+ CAESinkFactory::EnumerateEx(m_sinkInfoList, true);
}
+ CLog::Log(LOGNOTICE, "Found %lu Lists of Devices", m_sinkInfoList.size());
+ PrintSinks();
}
CSoftAE::~CSoftAE()
@@ -179,6 +177,18 @@ void CSoftAE::OpenSink()
m_wake.Set();
}
+void CSoftAE::InternalCloseSink()
+{
+ /* close the old sink if it was open */
+ if (m_sink)
+ {
+ CExclusiveLock sinkLock(m_sinkLock);
+ m_sink->Drain();
+ m_sink->Deinitialize();
+ delete m_sink;
+ m_sink = NULL;
+ }
+}
/* this must NEVER be called from outside the main thread or Initialization */
void CSoftAE::InternalOpenSink()
{
@@ -305,15 +315,8 @@ void CSoftAE::InternalOpenSink()
CExclusiveLock sinkLock(m_sinkLock);
reInit = true;
-
- /* we are going to open, so close the old sink if it was open */
- if (m_sink)
- {
- m_sink->Drain();
- m_sink->Deinitialize();
- delete m_sink;
- m_sink = NULL;
- }
+ //close the sink cause it gets reinited
+ InternalCloseSink();
/* get the display name of the device */
GetDeviceFriendlyName(device);
@@ -726,7 +729,8 @@ void CSoftAE::PauseStream(CSoftAEStream *stream)
stream->m_paused = true;
streamLock.Leave();
- OpenSink();
+ m_reOpen = true;
+ m_wake.Set();
}
void CSoftAE::ResumeStream(CSoftAEStream *stream)
@@ -737,7 +741,8 @@ void CSoftAE::ResumeStream(CSoftAEStream *stream)
streamLock.Leave();
m_streamsPlaying = true;
- OpenSink();
+ m_reOpen = true;
+ m_wake.Set();
}
void CSoftAE::Stop()
@@ -774,7 +779,7 @@ IAEStream *CSoftAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sample
CSoftAEStream *stream = new CSoftAEStream(dataFormat, sampleRate, encodedSampleRate, channelLayout, options);
m_newStreams.push_back(stream);
streamLock.Leave();
-
+ // this is really needed here
OpenSink();
return stream;
}
@@ -866,11 +871,9 @@ IAEStream *CSoftAE::FreeStream(IAEStream *stream)
CSingleLock lock(m_streamLock);
RemoveStream(m_playingStreams, (CSoftAEStream*)stream);
RemoveStream(m_streams , (CSoftAEStream*)stream);
- lock.Leave();
-
- /* if it was the master stream we need to reopen before deletion */
- if (m_masterStream == stream)
- OpenSink();
+ // Reopen is old behaviour. Not opening when masterstream stops means clipping on S/PDIF.
+ if(!m_isSuspended && (m_masterStream == stream))
+ m_reOpen = true;
delete (CSoftAEStream*)stream;
return NULL;
@@ -976,14 +979,67 @@ bool CSoftAE::Suspend()
CSoftAEStream *stream = *itt;
stream->Flush();
}
+ streamLock.Leave();
+ #if defined(TARGET_LINUX)
+ /*workaround sinks not playing sound after resume */
+ StopAllSounds();
+ bool ret = true;
+ if(m_sink)
+ {
+ /* Deinitialize and delete current m_sink */
+ // we don't want that Run reopens our device, so we wait.
+ m_saveSuspend.Reset();
+ // wait until we are looping in ProcessSuspend()
+ // this is more save to not come up unclean
+ // we cannot wait forever
+ ret = m_saveSuspend.WaitMSec(500);
+ if(ret)
+ {
+ CLog::Log(LOGDEBUG, "CSoftAE::Suspend - After Event");
+ CExclusiveLock sinkLock(m_sinkLock);
+ // remove all the sinks
+ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
+ {
+ itt->m_deviceInfoList.pop_back();
+ }
+ InternalCloseSink();
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CSoftAE::Suspend - Unload failed will continue");
+ m_saveSuspend.Reset();
+ }
+ }
+ // The device list is now empty and must be reenumerated afterwards.
+ if(ret)
+ m_sinkInfoList.clear();
+
+ // signal anybody, that we are gone now (beware of deadlocks)
+ // we don't unset the fields here, to care for reinit after resume
+ if(m_reOpen)
+ m_reOpenEvent.Set();
+ #endif
return true;
}
bool CSoftAE::Resume()
{
+#if defined(TARGET_LINUX)
+ // We must make sure, that we don't return empty.
+ if(m_sinkInfoList.empty())
+ {
+ CLog::Log(LOGDEBUG, "CSoftAE::Resume - Re Enumerating Sinks");
+ CExclusiveLock sinkLock(m_sinkLock);
+ // Forced enumeration - we are sure that we start completely fresh.
+ CAESinkFactory::EnumerateEx(m_sinkInfoList, true);
+ sinkLock.Leave(); // we leave here explicitly to not lock while printing new sinks
+ PrintSinks();
+ }
+#endif
CLog::Log(LOGDEBUG, "CSoftAE::Resume - Resuming AE processing");
m_isSuspended = false;
+ // we flag reopen
m_reOpen = true;
return true;
@@ -1000,11 +1056,12 @@ void CSoftAE::Run()
{
bool restart = false;
- if ((this->*m_outputStageFn)(hasAudio) > 0)
+ /* with the new non blocking implementation - we just reOpen here, when it tells reOpen */
+ if (!m_reOpen && (this->*m_outputStageFn)(hasAudio) > 0)
hasAudio = false; /* taken some audio - reset our silence flag */
/* if we have enough room in the buffer */
- if (m_buffer.Free() >= m_frameSize)
+ if (!m_reOpen && m_buffer.Free() >= m_frameSize)
{
/* take some data for our use from the buffer */
uint8_t *out = (uint8_t*)m_buffer.Take(m_frameSize);
@@ -1026,10 +1083,17 @@ void CSoftAE::Run()
/* if we are told to restart */
if (m_reOpen || restart || !m_sink)
{
+ if(m_sinkIsSuspended && m_sink)
+ {
+ // hint for fritsch: remember lazy evaluation
+ m_reOpen = !m_sink->SoftResume() || m_reOpen;
+ m_sinkIsSuspended = false;
+ CLog::Log(LOGDEBUG, "CSoftAE::Run - Sink was forgotten");
+ }
CLog::Log(LOGDEBUG, "CSoftAE::Run - Sink restart flagged");
InternalOpenSink();
- m_isSuspended = false; // exit Suspend state
}
+
#if defined(TARGET_ANDROID)
else if (m_playingStreams.empty()
&& m_playing_sounds.empty()
@@ -1280,12 +1344,29 @@ int CSoftAE::RunTranscodeStage(bool hasAudio)
return encodedFrames;
}
+void CSoftAE::PrintSinks()
+{
+ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
+ {
+ CLog::Log(LOGNOTICE, "Enumerated %s devices:", itt->m_sinkName.c_str());
+ int count = 0;
+ for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
+ {
+ CLog::Log(LOGNOTICE, " Device %d", ++count);
+ CAEDeviceInfo& info = *itt2;
+ std::stringstream ss((std::string)info);
+ std::string line;
+ while(std::getline(ss, line, '\n'))
+ CLog::Log(LOGNOTICE, " %s", line.c_str());
+ }
+ }
+}
+
unsigned int CSoftAE::RunRawStreamStage(unsigned int channelCount, void *out, bool &restart)
{
StreamList resumeStreams;
static StreamList::iterator itt;
CSingleLock streamLock(m_streamLock);
-
/* handle playing streams */
for (itt = m_playingStreams.begin(); itt != m_playingStreams.end(); ++itt)
{
@@ -1395,10 +1476,8 @@ inline void CSoftAE::RemoveStream(StreamList &streams, CSoftAEStream *stream)
inline void CSoftAE::ProcessSuspend()
{
- bool sinkIsSuspended = false;
unsigned int curSystemClock = 0;
-
-#if defined(TARGET_WINDOWS)
+#if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
if (!m_softSuspend && m_playingStreams.empty() && m_playing_sounds.empty() &&
!g_advancedSettings.m_streamSilence)
{
@@ -1410,37 +1489,54 @@ inline void CSoftAE::ProcessSuspend()
if (m_softSuspend)
curSystemClock = XbmcThreads::SystemClockMillis();
#endif
-
/* idle while in Suspend() state until Resume() called */
/* idle if nothing to play and user hasn't enabled */
/* continuous streaming (silent stream) in as.xml */
- while ((m_isSuspended || (m_softSuspend && (curSystemClock > m_softSuspendTimer))) &&
- m_running && !m_reOpen)
+ /* In case of Suspend stay in there until Resume is called from outer thread */
+ while (m_isSuspended || ((m_softSuspend && (curSystemClock > m_softSuspendTimer)) &&
+ m_running && !m_reOpen))
{
- if (m_sink && !sinkIsSuspended)
+ if (!m_isSuspended && m_sink && !m_sinkIsSuspended)
{
/* put the sink in Suspend mode */
CExclusiveLock sinkLock(m_sinkLock);
- if (!m_sink->SoftSuspend())
+ if (m_sink && !m_sink->SoftSuspend())
{
- sinkIsSuspended = false; //sink cannot be suspended
+ m_sinkIsSuspended = false; //sink cannot be suspended
m_softSuspend = false; //break suspend loop
break;
}
else
- sinkIsSuspended = true; //sink has suspended processing
+ {
+ CLog::Log(LOGDEBUG, "Suspended the Sink");
+ m_sinkIsSuspended = true; //sink has suspended processing
+ }
sinkLock.Leave();
}
+ // Signal that the Suspend can go on now.
+ // Idea: Outer thread calls Suspend() - but
+ // because of AddPackets does not care about locks, we must make
+ // sure, that our school bus (AE::Run) is currently driving through
+ // some gas station, before we move away the sink.
+ if(m_isSuspended)
+ m_saveSuspend.Set();
/* idle for platform-defined time */
m_wake.WaitMSec(SOFTAE_IDLE_WAIT_MSEC);
- /* check if we need to resume for stream or sound */
+ /* check if we need to resume for stream or sound or somebody wants to open us
+ * the suspend checks are only there to:
+ * a) not run out of softSuspend directly when we are sleeping
+ * b) nail(!) the thread during real Suspend into this method
+ * Note: It is not enough to check the streams buffer, cause it might not be filled yet
+ * We have to check after ProcessSuspending() if the sink is still in softsleep and resume it
+ */
if (!m_isSuspended && (!m_playingStreams.empty() || !m_playing_sounds.empty()))
{
- m_reOpen = !m_sink->SoftResume(); // sink returns false if it requires reinit
- sinkIsSuspended = false; //sink processing data
- m_softSuspend = false; //break suspend loop
+ m_reOpen = !m_sink->SoftResume() || m_reOpen; // sink returns false if it requires reinit (worthless with current implementation)
+ m_sinkIsSuspended = false; //sink processing data
+ m_softSuspend = false; //break suspend loop (under some conditions)
+ CLog::Log(LOGDEBUG, "Resumed the Sink");
break;
}
}
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
index 56fb41712379f..26d5e9c72127e 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -116,6 +116,7 @@ class CSoftAE : public IThreadedAE
void OpenSink();
void InternalOpenSink();
+ void InternalCloseSink();
void ResetEncoder();
bool SetupEncoder(AEAudioFormat &format);
void Deinitialize();
@@ -136,11 +137,13 @@ class CSoftAE : public IThreadedAE
/* internal vars */
bool m_running, m_reOpen;
+ bool m_sinkIsSuspended; /* The sink is in unusable state, e.g. SoftSuspended */
bool m_isSuspended; /* engine suspended by external function to release audio context */
bool m_softSuspend; /* latches after last stream or sound played for timer below for idle */
unsigned int m_softSuspendTimer; /* time in milliseconds to hold sink open before soft suspend for idle */
CEvent m_reOpenEvent;
CEvent m_wake;
+ CEvent m_saveSuspend;
CCriticalSection m_runningLock; /* released when the thread exits */
CCriticalSection m_streamLock; /* m_streams lock */
@@ -242,5 +245,6 @@ class CSoftAE : public IThreadedAE
void RunNormalizeStage (unsigned int channelCount, void *out, unsigned int mixed);
void RemoveStream(StreamList &streams, CSoftAEStream *stream);
+ void PrintSinks();
};
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
index c6d50658c5d42..f9cace57f953a 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
index 18225880a0f57..cd50c0b47565a 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
index b61f46b36e476..258dcaca56b7a 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -485,7 +485,6 @@ double CSoftAEStream::GetDelay()
double delay = AE.GetDelay();
delay += (double)(m_inputBuffer.Used() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
delay += (double)m_framesBuffered / (double)AE.GetSampleRate();
-
return delay;
}
@@ -494,10 +493,9 @@ double CSoftAEStream::GetCacheTime()
if (m_delete)
return 0.0;
- double time;
- time = (double)(m_inputBuffer.Used() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
- time += (double)(m_waterLevel - m_framesBuffered) / (double)AE.GetSampleRate();
- time += AE.GetCacheTime();
+ double time = AE.GetCacheTime();
+ time += (double)(m_inputBuffer.Used() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
+ time += (double)m_framesBuffered / (double)AE.GetSampleRate();
return time;
}
@@ -506,10 +504,9 @@ double CSoftAEStream::GetCacheTotal()
if (m_delete)
return 0.0;
- double total;
- total = (double)(m_inputBuffer.Size() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
+ double total = AE.GetCacheTotal();
+ total += (double)(m_inputBuffer.Size() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
total += (double)m_waterLevel / (double)AE.GetSampleRate();
- total += AE.GetCacheTotal();
return total;
}
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
index 7e93215f9161b..571dc8864747f 100644
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
+++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/AE.h b/xbmc/cores/AudioEngine/Interfaces/AE.h
index 0baba37c50c60..cbfa8ed3998e0 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AE.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AE.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h b/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h
index 9613d029d7f1c..055f28bef87dc 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/AESink.h b/xbmc/cores/AudioEngine/Interfaces/AESink.h
index a67b860b41fbe..97ea571015357 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AESink.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AESink.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/AESound.h b/xbmc/cores/AudioEngine/Interfaces/AESound.h
index 100efdbed425e..ebbcc0d7ee8ab 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AESound.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AESound.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/AEStream.h b/xbmc/cores/AudioEngine/Interfaces/AEStream.h
index 060fcb9ebf7bb..67fa5e2a0fb41 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AEStream.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AEStream.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Interfaces/ThreadedAE.h b/xbmc/cores/AudioEngine/Interfaces/ThreadedAE.h
index 41053291babe0..82e4936b4491a 100644
--- a/xbmc/cores/AudioEngine/Interfaces/ThreadedAE.h
+++ b/xbmc/cores/AudioEngine/Interfaces/ThreadedAE.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
index 91218a48c3d4d..3997f90874dbc 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -33,12 +33,11 @@
#include "utils/MathUtils.h"
#include "threads/SingleLock.h"
#include "settings/GUISettings.h"
-#if defined(HAS_AMLPLAYER)
-#include "cores/amlplayer/AMLUtils.h"
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
+#include "utils/AMLUtils.h"
#endif
#define ALSA_OPTIONS (SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_FORMAT | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_RESAMPLE)
-#define ALSA_PERIODS 16
#define ALSA_MAX_CHANNELS 16
static enum AEChannel ALSAChannelMap[ALSA_MAX_CHANNELS + 1] = {
@@ -144,7 +143,7 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
m_channelLayout = GetChannelLayout(format);
m_passthrough = false;
}
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
if (aml_present())
{
aml_set_audio_passthrough(m_passthrough);
@@ -259,6 +258,27 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
unsigned int sampleRate = format.m_sampleRate;
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
+ // alsa/kernel lies, so map everything to 44100 or 48000
+ switch(sampleRate)
+ {
+ case 11025:
+ case 22050:
+ case 88200:
+ case 176400:
+ sampleRate = 44100;
+ break;
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 96000:
+ case 192000:
+ case 384000:
+ sampleRate = 48000;
+ break;
+ }
+#endif
unsigned int channelCount = format.m_channelLayout.Count();
snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL);
snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);
@@ -328,59 +348,25 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
}
}
- unsigned int periods;
-
snd_pcm_uframes_t periodSize, bufferSize;
snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);
- bufferSize = std::min(bufferSize, (snd_pcm_uframes_t)8192);
- periodSize = bufferSize / ALSA_PERIODS;
- periods = ALSA_PERIODS;
+ bufferSize = std::min(bufferSize, (snd_pcm_uframes_t) 256 * 1024);
+ periodSize = 1024;
- CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
+ CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
- /* work on a copy of the hw params */
- snd_pcm_hw_params_t *hw_params_copy;
- snd_pcm_hw_params_alloca(&hw_params_copy);
+ /* try to set the period size and the buffer size*/
+ snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params, &periodSize, NULL);
+ snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params, &bufferSize);
- /* try to set the buffer size then the period size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
+ if(snd_pcm_hw_params(m_pcm, hw_params) != 0)
{
- /* try to set the period size then the buffer size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
- {
- /* try to just set the buffer size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
- {
- /* try to just set the period size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
- {
- CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters");
- return false;
- }
- }
- }
+ CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters");
+ return false;
}
- snd_pcm_hw_params_get_period_size(hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_get_buffer_size(hw_params_copy, &bufferSize);
-
-
- CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
+ CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
/* set the format parameters */
format.m_sampleRate = sampleRate;
@@ -426,7 +412,6 @@ void CAESinkALSA::Deinitialize()
if (m_pcm)
{
- snd_pcm_drop (m_pcm);
snd_pcm_close(m_pcm);
m_pcm = NULL;
}
@@ -487,7 +472,13 @@ double CAESinkALSA::GetCacheTotal()
unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
{
if (!m_pcm)
- return 0;
+ {
+ SoftResume();
+ if(!m_pcm)
+ return 0;
+
+ CLog::Log(LOGDEBUG, "CAESinkALSA - the grAEken is hunger, feed it (I am the downmost fallback - fix your code)");
+ }
int ret;
@@ -676,12 +667,17 @@ bool CAESinkALSA::OpenPCMDevice(const std::string &name, const std::string ¶
return false;
}
-void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list)
+void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
{
/* ensure that ALSA has been initialized */
snd_lib_error_set_handler(sndLibErrorHandler);
- if(!snd_config)
+ if(!snd_config || force)
+ {
+ if(force)
+ snd_config_update_free_global();
+
snd_config_update();
+ }
snd_config_t *config;
snd_config_copy(&config, snd_config);
@@ -1125,6 +1121,28 @@ bool CAESinkALSA::GetELD(snd_hctl_t *hctl, int device, CAEDeviceInfo& info, bool
return true;
}
+bool CAESinkALSA::SoftSuspend()
+{
+ if(m_pcm) // it is still there
+ Deinitialize();
+
+ return true;
+}
+bool CAESinkALSA::SoftResume()
+{
+ // reinit all the clibber
+ bool ret = true; // all fine
+ if(!m_pcm)
+ {
+ if (!snd_config)
+ snd_config_update();
+
+ ret = Initialize(m_initFormat, m_initDevice);
+ }
+ //we want that AE loves us again - reinit when initialize failed
+ return ret; // force reinit if false
+}
+
void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
{
va_list arg;
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
index db1ba802901f9..fb4efb0329324 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -49,8 +49,10 @@ class CAESinkALSA : public IAESink
virtual double GetCacheTotal ();
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
+ virtual bool SoftSuspend();
+ virtual bool SoftResume();
- static void EnumerateDevicesEx(AEDeviceInfoList &list);
+ static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
private:
CAEChannelInfo GetChannelLayout(AEAudioFormat format);
void GetAESParams(const AEAudioFormat format, std::string& params);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
index b885caa99002a..48473e06634c6 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -23,8 +23,8 @@
#include "Utils/AERingBuffer.h"
#include "android/activity/XBMCApp.h"
#include "utils/log.h"
-#if defined(HAS_AMLPLAYER)
-#include "cores/amlplayer/AMLUtils.h"
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
+#include "utils/AMLUtils.h"
#endif
#include
@@ -72,14 +72,14 @@ CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
{
m_sinkbuffer = NULL;
m_alignedS16LE = NULL;
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
aml_cpufreq_limit(true);
#endif
}
CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
{
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
aml_cpufreq_limit(false);
#endif
}
@@ -88,6 +88,16 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
{
m_format = format;
+ if (AE_IS_RAW(m_format.m_dataFormat))
+ m_passthrough = true;
+ else
+ m_passthrough = false;
+
+#if defined(HAS_LIBAMCODEC)
+ if (aml_present())
+ aml_set_audio_passthrough(m_passthrough);
+#endif
+
// default to 44100, all android devices support it.
// then check if we can support the requested rate.
unsigned int sampleRate = 44100;
@@ -228,13 +238,16 @@ bool CAESinkAUDIOTRACK::HasVolume()
return true;
}
-void CAESinkAUDIOTRACK::SetVolume(float volume)
+void CAESinkAUDIOTRACK::SetVolume(float scale)
{
- m_volume = volume;
- m_volume_changed = true;
+ // Android uses fixed steps, reverse scale back to percent
+ float gain = CAEUtil::ScaleToGain(scale);
+ m_volume = CAEUtil::GainToPercent(gain);
+ if (!m_passthrough)
+ m_volume_changed = true;
}
-void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list)
+void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
{
m_info.m_channels.Reset();
m_info.m_dataFormats.clear();
@@ -273,7 +286,6 @@ void CAESinkAUDIOTRACK::Process()
jmethodID jmRelease = jenv->GetMethodID(jcAudioTrack, "release", "()V");
jmethodID jmWrite = jenv->GetMethodID(jcAudioTrack, "write", "([BII)I");
jmethodID jmPlayState = jenv->GetMethodID(jcAudioTrack, "getPlayState", "()I");
- jmethodID jmSetStereoVolume = jenv->GetMethodID(jcAudioTrack, "setStereoVolume", "(FF)I");
jmethodID jmPlayHeadPosition = jenv->GetMethodID(jcAudioTrack, "getPlaybackHeadPosition", "()I");
jmethodID jmGetMinBufferSize = jenv->GetStaticMethodID(jcAudioTrack, "getMinBufferSize", "(III)I");
@@ -302,6 +314,12 @@ void CAESinkAUDIOTRACK::Process()
min_buffer_size,
GetStaticIntField(jenv, "AudioTrack", "MODE_STREAM"));
+ // Set the initial volume
+ float volume = 1.0;
+ if (!m_passthrough)
+ volume = m_volume;
+ CXBMCApp::SetSystemVolume(jenv, volume);
+
// The AudioTrack object has been created and waiting to play,
m_inited.Set();
// yield to give other threads a chance to do some work.
@@ -318,12 +336,11 @@ void CAESinkAUDIOTRACK::Process()
while (!m_bStop)
{
- if (m_volume_changed)
+ if (m_volume_changed && !m_passthrough)
{
// check of volume changes and make them,
// do it here to keep jni calls local to this thread.
- jfloat jvolume = m_volume;
- jenv->CallIntMethod(joAudioTrack, jmSetStereoVolume, jvolume, jvolume);
+ CXBMCApp::SetSystemVolume(jenv, m_volume);
m_volume_changed = false;
}
if (m_draining)
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
index e7ac7fce44802..901139009be89 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -42,8 +42,8 @@ class CAESinkAUDIOTRACK : public CThread, public IAESink
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
virtual bool HasVolume ();
- virtual void SetVolume (float volume);
- static void EnumerateDevicesEx(AEDeviceInfoList &list);
+ virtual void SetVolume (float scale);
+ static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
private:
virtual void Process();
@@ -62,6 +62,8 @@ class CAESinkAUDIOTRACK : public CThread, public IAESink
CEvent m_wake;
CEvent m_inited;
volatile bool m_draining;
+ bool m_passthrough;
+
double m_audiotrackbuffer_sec;
double m_audiotrack_empty_sec;
};
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp
index 4d3d41e205a65..ac58eb685d025 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -464,7 +464,7 @@ double CAESinkDirectSound::GetCacheTotal()
return (double)m_dwBufferLen / (double)m_AvgBytesPerSec;
}
-void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
+void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
{
CAEDeviceInfo deviceInfo;
@@ -603,10 +603,10 @@ void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
if (SUCCEEDED(hr) && varName.blob.cbSize > 0)
{
WAVEFORMATEX* smpwfxex = (WAVEFORMATEX*)varName.blob.pBlobData;
- deviceInfo.m_channels = layoutsByChCount[std::min(smpwfxex->nChannels, (WORD) 2)];
+ deviceInfo.m_channels = layoutsByChCount[std::max(std::min(smpwfxex->nChannels, (WORD) 8), (WORD) 2)];
deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT));
deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
- deviceInfo.m_sampleRates.push_back(std::min(smpwfxex->nSamplesPerSec, (DWORD) 96000));
+ deviceInfo.m_sampleRates.push_back(std::min(smpwfxex->nSamplesPerSec, (DWORD) 192000));
}
else
{
@@ -622,12 +622,25 @@ void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
deviceInfo.m_displayNameExtra = std::string("DirectSound: ").append(strFriendlyName);
deviceInfo.m_deviceType = aeDeviceType;
- /* Now logged by AESinkFactory on startup */
- //CLog::Log(LOGDEBUG,"Audio Device %d: %s", i, ((std::string)deviceInfo).c_str());
-
deviceInfoList.push_back(deviceInfo);
}
+ // since AE takes the first device in deviceInfoList as default audio device we need
+ // to sort it in order to use the real default device
+ if(deviceInfoList.size() > 1)
+ {
+ std::string strDD = GetDefaultDevice();
+ for (AEDeviceInfoList::iterator itt = deviceInfoList.begin(); itt != deviceInfoList.end(); ++itt)
+ {
+ CAEDeviceInfo devInfo = *itt;
+ if(devInfo.m_deviceName == strDD)
+ {
+ deviceInfoList.erase(itt);
+ deviceInfoList.insert(deviceInfoList.begin(), devInfo);
+ }
+ }
+ }
+
return;
failed:
@@ -825,5 +838,61 @@ const char *CAESinkDirectSound::WASAPIErrToStr(HRESULT err)
return NULL;
}
+std::string CAESinkDirectSound::GetDefaultDevice()
+{
+ IMMDeviceEnumerator* pEnumerator = NULL;
+ IMMDevice* pDevice = NULL;
+ IPropertyStore* pProperty = NULL;
+ HRESULT hr;
+ PROPVARIANT varName;
+ std::string strDevName = "default";
+
+ hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
+ if (FAILED(hr))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %s", WASAPIErrToStr(hr));
+ goto failed;
+ }
+
+ hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
+ if (FAILED(hr))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Retrieval of audio endpoint enumeration failed.");
+ goto failed;
+ }
+
+ hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
+ if (FAILED(hr))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint properties failed.");
+ goto failed;
+ }
+
+ PropVariantInit(&varName);
+ hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
+ if (FAILED(hr))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint form factor failed.");
+ goto failed;
+ }
+ AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
+ PropVariantClear(&varName);
+
+ hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
+ if (FAILED(hr))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint GUID failed.");
+ goto failed;
+ }
+ strDevName = localWideToUtf(varName.pwszVal);
+ PropVariantClear(&varName);
+failed:
+
+ SAFE_RELEASE(pProperty);
+ SAFE_RELEASE(pDevice);
+ SAFE_RELEASE(pEnumerator);
+
+ return strDevName;
+}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h
index 9f54090976588..dbf961862d781 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -43,7 +43,8 @@ class CAESinkDirectSound : public IAESink
virtual double GetCacheTime ();
virtual double GetCacheTotal ();
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
- static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
+ static std::string GetDefaultDevice ();
+ static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList, bool force = false);
private:
void AEChannelsFromSpeakerMask(DWORD speakers);
DWORD SpeakerMaskFromAEChannels(const CAEChannelInfo &channels);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp
index 1468d6aa9f9ce..5f86d34e4e5f8 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h
index 67e55d648d98e..e6413fcff6d8e 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp
index 06b9a7fc4ffc7..1af9912bc27e3 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -427,7 +427,7 @@ void CAESinkOSS::Drain()
// ???
}
-void CAESinkOSS::EnumerateDevicesEx(AEDeviceInfoList &list)
+void CAESinkOSS::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
{
int mixerfd;
const char * mixerdev = "/dev/mixer";
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h
index aa8a9f8f9a73f..c8c1179e1e919 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@ class CAESinkOSS : public IAESink
virtual double GetCacheTotal () { return 0.0; } /* FIXME */
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual void Drain ();
- static void EnumerateDevicesEx(AEDeviceInfoList &list);
+ static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
private:
int m_fd;
std::string m_device;
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp
index 200167721e6d2..56af30e60f764 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h
index eb4ad0a0f8370..4718406971284 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
index 8475d60f7e847..de5ed0ed2a914 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -559,7 +559,7 @@ bool CAESinkWASAPI::SoftResume()
return false;
}
-void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
+void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
{
IMMDeviceEnumerator* pEnumerator = NULL;
IMMDeviceCollection* pEnumDevices = NULL;
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
index a0c567ae7b17d..c504892b42d2e 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
@@ -1,6 +1,6 @@
#pragma once
/*
-* Copyright (C) 2010-2012 Team XBMC
+* Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -45,7 +45,7 @@ class CAESinkWASAPI : public IAESink
virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
virtual bool SoftSuspend ();
virtual bool SoftResume ();
- static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
+ static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList, bool force = false);
private:
bool InitializeExclusive(AEAudioFormat &format);
void AEChannelsFromSpeakerMask(DWORD speakers);
@@ -78,4 +78,4 @@ class CAESinkWASAPI : public IAESink
unsigned int m_uiBufferLen; /* wasapi endpoint buffer size, in frames */
double m_avgTimeWaiting; /* time between next buffer of data from SoftAE and driver call for data */
double m_sinkLatency; /* time in seconds of total duration of the two WASAPI buffers */
-};
\ No newline at end of file
+};
diff --git a/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.cpp b/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.cpp
index 9eed30a099c2c..e3c790bc23dc2 100644
--- a/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.h b/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.h
index bc40d57238dc8..69ab06775ea8b 100644
--- a/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.h
+++ b/xbmc/cores/AudioEngine/Utils/AEBitstreamPacker.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEBuffer.cpp b/xbmc/cores/AudioEngine/Utils/AEBuffer.cpp
index b36f43464d225..a79a6949fc1d9 100644
--- a/xbmc/cores/AudioEngine/Utils/AEBuffer.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEBuffer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEBuffer.h b/xbmc/cores/AudioEngine/Utils/AEBuffer.h
index aaaa69cfa0dc7..442a698557840 100644
--- a/xbmc/cores/AudioEngine/Utils/AEBuffer.h
+++ b/xbmc/cores/AudioEngine/Utils/AEBuffer.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
index 0abfafd681e12..265a33917192c 100644
--- a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.h b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.h
index 1cd47dab53a79..438f085abf19a 100644
--- a/xbmc/cores/AudioEngine/Utils/AEChannelInfo.h
+++ b/xbmc/cores/AudioEngine/Utils/AEChannelInfo.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp
index 2e4da191c8c50..a4e47552e01a5 100644
--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.h b/xbmc/cores/AudioEngine/Utils/AEConvert.h
index 03764ffa56df3..46472486aafc3 100644
--- a/xbmc/cores/AudioEngine/Utils/AEConvert.h
+++ b/xbmc/cores/AudioEngine/Utils/AEConvert.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.cpp b/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.cpp
index 90ab05b738077..b4a5c5ba41bc0 100644
--- a/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Team XBMC
+ * Copyright (C) 2012-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.h b/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.h
index 04784fac30186..2cd80a198a062 100644
--- a/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.h
+++ b/xbmc/cores/AudioEngine/Utils/AEDeviceInfo.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2012 Team XBMC
+ * Copyright (C) 2012-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEELDParser.cpp b/xbmc/cores/AudioEngine/Utils/AEELDParser.cpp
index da5c6d320b71d..ff9f2c78d53a6 100644
--- a/xbmc/cores/AudioEngine/Utils/AEELDParser.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEELDParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Team XBMC
+ * Copyright (C) 2012-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEELDParser.h b/xbmc/cores/AudioEngine/Utils/AEELDParser.h
index fdbbf1f1dbf40..09984627be5ac 100644
--- a/xbmc/cores/AudioEngine/Utils/AEELDParser.h
+++ b/xbmc/cores/AudioEngine/Utils/AEELDParser.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2012 Team XBMC
+ * Copyright (C) 2012-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AELimiter.cpp b/xbmc/cores/AudioEngine/Utils/AELimiter.cpp
index 1de88bc58aa9c..77af32053239b 100644
--- a/xbmc/cores/AudioEngine/Utils/AELimiter.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AELimiter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AELimiter.h b/xbmc/cores/AudioEngine/Utils/AELimiter.h
index decc5f4028c16..ef46d0cbb46b8 100644
--- a/xbmc/cores/AudioEngine/Utils/AELimiter.h
+++ b/xbmc/cores/AudioEngine/Utils/AELimiter.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.cpp b/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.cpp
index 27bb343e74c50..9fc0689fed2b7 100644
--- a/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.h b/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.h
index 30918027ca936..97016f65e4940 100644
--- a/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.h
+++ b/xbmc/cores/AudioEngine/Utils/AEPackIEC61937.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AERemap.cpp b/xbmc/cores/AudioEngine/Utils/AERemap.cpp
index 6e44bff192826..1e9da80034ea9 100644
--- a/xbmc/cores/AudioEngine/Utils/AERemap.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AERemap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AERemap.h b/xbmc/cores/AudioEngine/Utils/AERemap.h
index 49e984b1f242a..1b35e37916896 100644
--- a/xbmc/cores/AudioEngine/Utils/AERemap.h
+++ b/xbmc/cores/AudioEngine/Utils/AERemap.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AERingBuffer.h b/xbmc/cores/AudioEngine/Utils/AERingBuffer.h
index b7e18fbe32087..17c9d0ca4ce50 100644
--- a/xbmc/cores/AudioEngine/Utils/AERingBuffer.h
+++ b/xbmc/cores/AudioEngine/Utils/AERingBuffer.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp
index bfe5f3591ac6f..876f5b6c159f7 100644
--- a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h
index c4c06c1f5378f..3c67a375804c3 100644
--- a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h
+++ b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
index 4f1b644607c61..6de84dc5d993c 100644
--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h
index be52f6321c751..458dc00e39669 100644
--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h
+++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -71,6 +71,19 @@ class CAEUtil
return (value - 1)*db_range;
}
+ /*! \brief convert a dB gain to volume percentage (as a proportion)
+ We assume a dB range of 60dB, i.e. assume that 0% volume corresponds
+ to a reduction of 60dB.
+ \param the corresponding gain in dB from -60dB .. 0dB.
+ \return value the volume from 0..1
+ \sa ScaleToGain
+ */
+ static inline const float GainToPercent(const float gain)
+ {
+ static const float db_range = 60.0f;
+ return 1+(gain/db_range);
+ }
+
/*! \brief convert a dB gain to a scale factor for audio manipulation
Inverts gain = 20 log_10(scale)
\param dB the gain in decibels.
@@ -82,6 +95,17 @@ class CAEUtil
return pow(10.0f, dB/20);
}
+ /*! \brief convert a scale factor to dB gain for audio manipulation
+ Inverts GainToScale result
+ \param the scale factor (equivalent to a voltage multiplier).
+ \return dB the gain in decibels.
+ \sa GainToScale
+ */
+ static inline const float ScaleToGain(const float scale)
+ {
+ return 20*log10(scale);
+ }
+
#ifdef __SSE__
static void SSEMulArray (float *data, const float mul, uint32_t count);
static void SSEMulAddArray (float *data, float *add, const float mul, uint32_t count);
diff --git a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
index fb24d1ac7df2f..c8a521c80da44 100644
--- a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.h b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.h
index ac4c9b5503abd..2ed33eee91c1c 100644
--- a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.h
+++ b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.h
@@ -1,6 +1,6 @@
#pragma once
/*
- * Copyright (C) 2010-2012 Team XBMC
+ * Copyright (C) 2010-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
index a54ff31a62b59..2a502fcafc91f 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
@@ -66,6 +66,12 @@ void CBaseRenderer::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCa
m_RenderUpdateCallBackCtx = ctx;
}
+void CBaseRenderer::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
+{
+ m_RenderFeaturesCallBackFn = fn;
+ m_RenderFeaturesCallBackCtx = ctx;
+}
+
void CBaseRenderer::ChooseBestResolution(float fps)
{
if (fps == 0.0) return;
diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h
index 81d21d86041c0..21952c8cfe6b1 100644
--- a/xbmc/cores/VideoRenderers/BaseRenderer.h
+++ b/xbmc/cores/VideoRenderers/BaseRenderer.h
@@ -23,6 +23,7 @@
#include "guilib/Resolution.h"
#include "guilib/Geometry.h"
#include "RenderFormats.h"
+#include "RenderFeatures.h"
#define MAX_PLANES 3
#define MAX_FIELDS 3
@@ -48,24 +49,8 @@ enum EFIELDSYNC
FS_BOT
};
-enum ERENDERFEATURE
-{
- RENDERFEATURE_GAMMA,
- RENDERFEATURE_BRIGHTNESS,
- RENDERFEATURE_CONTRAST,
- RENDERFEATURE_NOISE,
- RENDERFEATURE_SHARPNESS,
- RENDERFEATURE_NONLINSTRETCH,
- RENDERFEATURE_ROTATION,
- RENDERFEATURE_STRETCH,
- RENDERFEATURE_CROP,
- RENDERFEATURE_ZOOM,
- RENDERFEATURE_VERTICAL_SHIFT,
- RENDERFEATURE_PIXEL_RATIO,
- RENDERFEATURE_POSTPROCESS
-};
-
typedef void (*RenderUpdateCallBackFn)(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
+typedef void (*RenderFeaturesCallBackFn)(const void *ctx, Features &renderFeatures);
struct DVDVideoPicture;
@@ -91,6 +76,7 @@ class CBaseRenderer
std::vector SupportedFormats() { return std::vector(); }
virtual void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
+ virtual void RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn);
protected:
void ChooseBestResolution(float fps);
@@ -131,4 +117,7 @@ class CBaseRenderer
const void* m_RenderUpdateCallBackCtx;
RenderUpdateCallBackFn m_RenderUpdateCallBackFn;
+
+ const void* m_RenderFeaturesCallBackCtx;
+ RenderFeaturesCallBackFn m_RenderFeaturesCallBackFn;
};
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
index cb0939fef6c2a..dff74869954ed 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
@@ -193,10 +193,22 @@ bool CLinuxRendererGLES::Configure(unsigned int width, unsigned int height, unsi
m_RenderUpdateCallBackCtx = NULL;
if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
{
+ m_renderFeatures.clear();
+ m_scalingMethods.clear();
+ m_deinterlaceModes.clear();
+ m_deinterlaceMethods.clear();
+
+ if (m_RenderFeaturesCallBackFn)
+ {
+ (*m_RenderFeaturesCallBackFn)(m_RenderFeaturesCallBackCtx, m_renderFeatures);
+ // after setting up m_renderFeatures, we are done with the callback
+ m_RenderFeaturesCallBackFn = NULL;
+ m_RenderFeaturesCallBackCtx = NULL;
+ }
g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures);
- g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
- g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
g_application.m_pPlayer->GetScalingMethods(m_scalingMethods);
+ g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
+ g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
}
return true;
@@ -749,6 +761,8 @@ void CLinuxRendererGLES::UnInit()
m_bConfigured = false;
m_RenderUpdateCallBackFn = NULL;
m_RenderUpdateCallBackCtx = NULL;
+ m_RenderFeaturesCallBackFn = NULL;
+ m_RenderFeaturesCallBackCtx = NULL;
}
inline void CLinuxRendererGLES::ReorderDrawPoints()
@@ -1352,7 +1366,7 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
// OpenGLES returns in RGBA order but CRenderCapture needs BGRA order
// XOR Swap RGBA -> BGRA
unsigned char* pixels = (unsigned char*)capture->GetRenderBuffer();
- for (int i = 0; i < capture->GetWidth() * capture->GetHeight(); i++, pixels+=4)
+ for (unsigned int i = 0; i < capture->GetWidth() * capture->GetHeight(); i++, pixels+=4)
{
std::swap(pixels[0], pixels[2]);
}
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
index 76b543762b97e..8953de47d72a6 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
@@ -29,6 +29,7 @@
#include "xbmc/guilib/Shader.h"
#include "settings/VideoSettings.h"
#include "RenderFlags.h"
+#include "RenderFeatures.h"
#include "guilib/GraphicContext.h"
#include "BaseRenderer.h"
#include "xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
@@ -39,7 +40,6 @@ class CBaseTexture;
namespace Shaders { class BaseYUV2RGBShader; }
namespace Shaders { class BaseVideoFilterShader; }
class COpenMaxVideo;
-typedef std::vector Features;
#define NUM_BUFFERS 3
diff --git a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
index 4375d19caeb1b..28b821bdb029b 100644
--- a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
+++ b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp
@@ -521,6 +521,7 @@ void COverlayTextureGL::Render(SRenderState& state)
GLint posLoc = g_Windowing.GUIShaderGetPos();
GLint colLoc = g_Windowing.GUIShaderGetCol();
GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
+ GLint uniColLoc= g_Windowing.GUIShaderGetUniCol();
glVertexAttribPointer(posLoc, 2, GL_FLOAT, 0, 0, ver);
glVertexAttribPointer(colLoc, 4, GL_FLOAT, 0, 0, col);
@@ -536,6 +537,7 @@ void COverlayTextureGL::Render(SRenderState& state)
col[i][0] = col[i][1] = col[i][2] = col[i][3] = 1.0f;
}
+ glUniform4f(uniColLoc,(col[0][0]), (col[0][1]), (col[0][2]), (col[0][3]));
// Setup vertex position values
ver[0][0] = ver[3][0] = rd.left;
ver[0][1] = ver[1][1] = rd.top;
diff --git a/xbmc/cores/VideoRenderers/RenderFeatures.h b/xbmc/cores/VideoRenderers/RenderFeatures.h
new file mode 100644
index 0000000000000..82c2800c70a96
--- /dev/null
+++ b/xbmc/cores/VideoRenderers/RenderFeatures.h
@@ -0,0 +1,39 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * .
+ *
+ */
+
+enum ERENDERFEATURE
+{
+ RENDERFEATURE_GAMMA,
+ RENDERFEATURE_BRIGHTNESS,
+ RENDERFEATURE_CONTRAST,
+ RENDERFEATURE_NOISE,
+ RENDERFEATURE_SHARPNESS,
+ RENDERFEATURE_NONLINSTRETCH,
+ RENDERFEATURE_ROTATION,
+ RENDERFEATURE_STRETCH,
+ RENDERFEATURE_CROP,
+ RENDERFEATURE_ZOOM,
+ RENDERFEATURE_VERTICAL_SHIFT,
+ RENDERFEATURE_PIXEL_RATIO,
+ RENDERFEATURE_POSTPROCESS
+};
+
+typedef std::vector Features;
diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
index d22287dbfbb1c..86c5a38ef6d15 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -256,6 +256,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
CApplicationMessenger::Get().SwitchToFullscreen();
lock.Enter();
}
+ if( format & RENDER_FMT_BYPASS )
+ m_presentmethod = PRESENT_METHOD_BYPASS;
+
m_pRenderer->Update(false);
m_bIsStarted = true;
m_bReconfigured = true;
@@ -266,6 +269,11 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
return result;
}
+bool CXBMCRenderManager::RendererHandlesPresent()
+{
+ return IsConfigured() && m_presentmethod != PRESENT_METHOD_BYPASS;
+}
+
bool CXBMCRenderManager::IsConfigured()
{
if (!m_pRenderer)
@@ -653,6 +661,12 @@ void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpd
m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
}
+void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
+{
+ if (m_pRenderer)
+ m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
+}
+
void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
{
CSharedLock lock(m_sharedSection);
diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
index 7fe6bb234c5df..e28001ce13ce9 100644
--- a/xbmc/cores/VideoRenderers/RenderManager.h
+++ b/xbmc/cores/VideoRenderers/RenderManager.h
@@ -110,6 +110,8 @@ class CXBMCRenderManager
void UpdateResolution();
+ bool RendererHandlesPresent();
+
#ifdef HAS_GL
CLinuxRendererGL *m_pRenderer;
#elif HAS_GLES == 2
@@ -131,6 +133,7 @@ class CXBMCRenderManager
CSharedSection& GetSection() { return m_sharedSection; };
void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn);
+ void RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn);
protected:
void Render(bool clear, DWORD flags, DWORD alpha);
@@ -164,6 +167,7 @@ class CXBMCRenderManager
PRESENT_METHOD_BLEND,
PRESENT_METHOD_WEAVE,
PRESENT_METHOD_BOB,
+ PRESENT_METHOD_BYPASS,
};
double m_displayLatency;
diff --git a/xbmc/cores/amlplayer/AMLPlayer.cpp b/xbmc/cores/amlplayer/AMLPlayer.cpp
index ebf8f1c75f515..efc79440eefc4 100644
--- a/xbmc/cores/amlplayer/AMLPlayer.cpp
+++ b/xbmc/cores/amlplayer/AMLPlayer.cpp
@@ -27,6 +27,8 @@
#include "GUIInfoManager.h"
#include "video/VideoThumbLoader.h"
#include "Util.h"
+#include "cores/AudioEngine/AEFactory.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
#include "cores/VideoRenderers/RenderFlags.h"
#include "cores/VideoRenderers/RenderFormats.h"
#include "cores/VideoRenderers/RenderManager.h"
@@ -54,9 +56,23 @@
#include "settings/VideoSettings.h"
// amlogic libplayer
-#include "AMLUtils.h"
+#include "utils/AMLUtils.h"
#include "DllLibamplayer.h"
+static float VolumePercentToScale(float volume)
+{
+ float audio_volume = 0.0;
+ if (volume > VOLUME_MINIMUM)
+ {
+ float dB = CAEUtil::PercentToGain(volume);
+ audio_volume = CAEUtil::GainToScale(dB);
+ }
+ if (audio_volume >= 0.99f)
+ audio_volume = 1.0f;
+
+ return audio_volume;
+}
+
struct AMLChapterInfo
{
std::string name;
@@ -312,6 +328,20 @@ CAMLSubTitleThread::~CAMLSubTitleThread()
StopThread();
}
+void CAMLSubTitleThread::Flush()
+{
+ CSingleLock lock(m_subtitle_csection);
+ if (m_subtitle_strings.size())
+ {
+ // remove any expired subtitles
+ std::deque::iterator it = m_subtitle_strings.begin();
+ while (it != m_subtitle_strings.end())
+ {
+ it = m_subtitle_strings.erase(it);
+ }
+ }
+}
+
void CAMLSubTitleThread::UpdateSubtitle(CStdString &subtitle, int64_t elapsed_ms)
{
CSingleLock lock(m_subtitle_csection);
@@ -483,12 +513,14 @@ void CAMLSubTitleThread::Process(void)
}
else
{
- usleep(100 * 1000);
+ if (!m_bStop)
+ usleep(100 * 1000);
}
}
else
{
- usleep(250 * 1000);
+ if (!m_bStop)
+ usleep(250 * 1000);
}
}
m_subtitle_strings.clear();
@@ -519,6 +551,13 @@ CAMLPlayer::CAMLPlayer(IPlayerCallback &callback)
// for external subtitles
m_dvdOverlayContainer = new CDVDOverlayContainer;
m_dvdPlayerSubtitle = new CDVDPlayerSubtitle(m_dvdOverlayContainer);
+
+ // Suspend AE temporarily so exclusive or hog-mode sinks
+ // don't block external player's access to audio device
+ if (!CAEFactory::Suspend())
+ {
+ CLog::Log(LOGNOTICE,"%s: Failed to suspend AudioEngine before launching external player", __FUNCTION__);
+ }
}
CAMLPlayer::~CAMLPlayer()
@@ -528,6 +567,12 @@ CAMLPlayer::~CAMLPlayer()
delete m_dvdPlayerSubtitle;
delete m_dvdOverlayContainer;
delete m_dll, m_dll = NULL;
+
+ // Resume AE processing of XBMC native audio
+ if (!CAEFactory::Resume())
+ {
+ CLog::Log(LOGFATAL, "%s: Failed to restart AudioEngine after return from external player",__FUNCTION__);
+ }
}
bool CAMLPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
@@ -545,11 +590,14 @@ bool CAMLPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
m_item = file;
m_options = options;
+ m_pid = -1;
m_elapsed_ms = 0;
m_duration_ms = 0;
m_audio_info = "none";
m_audio_delay = 0;
+ m_audio_mute = g_settings.m_bMute;
+ m_audio_volume = VolumePercentToScale(g_settings.m_fVolumeLevel);
m_audio_passthrough_ac3 = g_guiSettings.GetBool("audiooutput.ac3passthrough");
m_audio_passthrough_dts = g_guiSettings.GetBool("audiooutput.dtspassthrough");
@@ -562,7 +610,6 @@ bool CAMLPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
m_subtitle_delay = 0;
m_subtitle_thread = NULL;
- m_chapter_index = 0;
m_chapter_count = 0;
m_show_mainvideo = -1;
@@ -573,6 +620,9 @@ bool CAMLPlayer::OpenFile(const CFileItem &file, const CPlayerOptions &options)
ClearStreamInfos();
+ if (m_item.IsDVDFile() || m_item.IsDVD())
+ return false;
+
// setup to spin the busy dialog until we are playing
m_ready.Reset();
@@ -780,7 +830,8 @@ float CAMLPlayer::GetPercentage()
void CAMLPlayer::SetMute(bool bOnOff)
{
m_audio_mute = bOnOff;
-#if !defined(TARGET_ANDROID)
+
+#if defined(HAS_AMLPLAYER_AUDIO_SETVOLUME)
CSingleLock lock(m_aml_csection);
if (m_dll->check_pid_valid(m_pid))
{
@@ -794,16 +845,10 @@ void CAMLPlayer::SetMute(bool bOnOff)
void CAMLPlayer::SetVolume(float volume)
{
- m_audio_volume = 0.0f;
- if (volume > VOLUME_MINIMUM)
- {
- float dB = CAEUtil::PercentToGain(volume);
- m_audio_volume = CAEUtil::GainToScale(dB);
- }
- if (m_audio_volume >= 0.99f)
- m_audio_volume = 1.0f;
+ // volume is a float percent from 0.0 to 1.0
+ m_audio_volume = VolumePercentToScale(volume);
-#if !defined(TARGET_ANDROID)
+#if defined(HAS_AMLPLAYER_AUDIO_SETVOLUME)
CSingleLock lock(m_aml_csection);
if (!m_audio_mute && m_dll->check_pid_valid(m_pid))
m_dll->audio_set_volume(m_pid, m_audio_volume);
@@ -886,11 +931,13 @@ void CAMLPlayer::SetAVDelay(float fValue)
CLog::Log(LOGDEBUG, "CAMLPlayer::SetAVDelay (%f)", fValue);
m_audio_delay = fValue * 1000.0;
+#if defined(HAS_AMLPLAYER_AUDIO_SETDELAY)
if (m_audio_streams.size() && m_dll->check_pid_valid(m_pid))
{
CSingleLock lock(m_aml_csection);
m_dll->audio_set_delay(m_pid, m_audio_delay);
}
+#endif
}
float CAMLPlayer::GetAVDelay()
@@ -953,9 +1000,15 @@ void CAMLPlayer::GetSubtitleName(int iStream, CStdString &strStreamName)
strStreamName = g_localizeStrings.Get(13205); // Unknown
}
if (m_log_level > 5)
- CLog::Log(LOGDEBUG, "CAMLPlayer::GetSubtitleName, iStream(%d)", iStream);
+ CLog::Log(LOGDEBUG, "CAMLPlayer::GetSubtitleName, iStream(%d), strStreamName(%s)",
+ iStream, strStreamName.c_str());
}
+void CAMLPlayer::GetSubtitleLanguage(int iStream, CStdString &strStreamLang)
+{
+ GetSubtitleName(iStream, strStreamLang);
+}
+
void CAMLPlayer::SetSubtitle(int iStream)
{
CSingleLock lock(m_aml_csection);
@@ -972,7 +1025,12 @@ void CAMLPlayer::SetSubtitle(int iStream)
return;
if (m_dll->check_pid_valid(m_pid) && m_subtitle_streams[m_subtitle_index]->source == STREAM_SOURCE_NONE)
+ {
m_dll->player_sid(m_pid, m_subtitle_streams[m_subtitle_index]->id);
+ aml_set_sysfs_int("/sys/class/subtitle/curr", m_subtitle_index);
+ if (m_subtitle_thread)
+ m_subtitle_thread->Flush();
+ }
else
{
m_dvdPlayerSubtitle->CloseStream(true);
@@ -992,12 +1050,19 @@ void CAMLPlayer::SetSubtitleVisible(bool bVisible)
if (m_subtitle_show && m_subtitle_count)
{
+ if (g_settings.m_currentVideoSettings.m_SubtitleStream < m_subtitle_count)
+ m_subtitle_index = g_settings.m_currentVideoSettings.m_SubtitleStream;
// on startup, if asked to show subs and SetSubtitle has not
// been called, we are expected to switch/show the 1st subtitle
if (m_subtitle_index < 0)
m_subtitle_index = 0;
if (m_dll->check_pid_valid(m_pid) && m_subtitle_streams[m_subtitle_index]->source == STREAM_SOURCE_NONE)
+ {
m_dll->player_sid(m_pid, m_subtitle_streams[m_subtitle_index]->id);
+ aml_set_sysfs_int("/sys/class/subtitle/curr", m_subtitle_index);
+ if (m_subtitle_thread)
+ m_subtitle_thread->Flush();
+ }
else
OpenSubtitleStream(m_subtitle_index);
}
@@ -1032,14 +1097,16 @@ int CAMLPlayer::GetChapterCount()
int CAMLPlayer::GetChapter()
{
+ // returns a one based value or zero if no chapters
GetStatus();
- for (int i = 0; i < m_chapter_count - 1; i++)
+ int chapter_index = -1;
+ for (int i = 0; i < m_chapter_count; i++)
{
- if (m_elapsed_ms >= m_chapters[i]->seekto_ms && m_elapsed_ms < m_chapters[i + 1]->seekto_ms)
- return i + 1;
+ if (m_elapsed_ms >= m_chapters[i]->seekto_ms)
+ chapter_index = i;
}
- return 0;
+ return chapter_index + 1;
}
void CAMLPlayer::GetChapterName(CStdString& strChapterName)
@@ -1092,7 +1159,7 @@ float CAMLPlayer::GetActualFPS()
return video_fps;
}
-void CAMLPlayer::SeekTime(__int64 seek_ms)
+void CAMLPlayer::SeekTime(int64_t seek_ms)
{
CSingleLock lock(m_aml_csection);
@@ -1112,17 +1179,15 @@ void CAMLPlayer::SeekTime(__int64 seek_ms)
m_dll->player_timesearch(m_pid, (float)seek_ms/1000.0);
WaitForSearchOK(5000);
WaitForPlaying(5000);
- // restore system volume setting.
- SetVolume(m_audio_volume);
}
}
-__int64 CAMLPlayer::GetTime()
+int64_t CAMLPlayer::GetTime()
{
return m_elapsed_ms;
}
-__int64 CAMLPlayer::GetTotalTime()
+int64_t CAMLPlayer::GetTotalTime()
{
return m_duration_ms;
}
@@ -1285,7 +1350,6 @@ void CAMLPlayer::OnStartup()
void CAMLPlayer::OnExit()
{
//CLog::Log(LOGNOTICE, "CAMLPlayer::OnExit()");
- Sleep(1000);
m_bStop = true;
// if we didn't stop playing, advance to the next item in xbmc's playlist
@@ -1387,6 +1451,33 @@ void CAMLPlayer::Process()
vfs_protocol.name = http_name;
url = "xb-" + url;
}
+ else if (url.Left(strlen("sftp://")).Equals("sftp://"))
+ {
+ // the name string needs to persist
+ static const char *http_name = "xb-sftp";
+ vfs_protocol.name = http_name;
+ url = "xb-" + url;
+ }
+ else if (url.Left(strlen("udp://")).Equals("udp://"))
+ {
+ std::string udp_params;
+ // bump up the default udp params for ffmpeg.
+ // ffmpeg will strip out 'dummy=10', we only add it
+ // to make the logic below with prpending '&' work right.
+ // to watch for udp errors, 'cat /proc/net/udp'
+ if (url.find("?") == std::string::npos)
+ udp_params.append("?dummy=10");
+ if (url.find("pkt_size=") == std::string::npos)
+ udp_params.append("&pkt_size=5264");
+ if (url.find("buffer_size=") == std::string::npos)
+ udp_params.append("&buffer_size=5390336");
+ // newer ffmpeg uses fifo_size instead of buf_size
+ if (url.find("buf_size=") == std::string::npos)
+ udp_params.append("&buf_size=5390336");
+
+ if (udp_params.size() > 0)
+ url.append(udp_params);
+ }
CLog::Log(LOGDEBUG, "CAMLPlayer::Process: URL=%s", url.c_str());
if (m_dll->player_init() != PLAYER_SUCCESS)
@@ -1395,7 +1486,7 @@ void CAMLPlayer::Process()
throw "CAMLPlayer::Process:player init failed";
}
CLog::Log(LOGDEBUG, "player init......");
- usleep(250 * 1000);
+ usleep(50 * 1000);
// must be after player_init
m_dll->av_register_protocol2(&vfs_protocol, sizeof(vfs_protocol));
@@ -1419,13 +1510,20 @@ void CAMLPlayer::Process()
play_control.need_start = 1; // if 0,you can omit player_start_play API.
// just play video/audio immediately.
// if 1,then need call "player_start_play" API;
- //play_control.auto_buffing_enable = 1;
- //play_control.buffing_min = 0.2;
- //play_control.buffing_middle = 0.5;
- //play_control.buffing_max = 0.8;
- //play_control.byteiobufsize =; // maps to av_open_input_file buffer size
- //play_control.loopbufsize =;
- //play_control.enable_rw_on_pause =;
+ play_control.displast_frame = 0; // 0:black out when player exit 1:keep last frame when player exit
+
+ // tweak player playback buffers for udp
+ if (url.Left(strlen("udp://")).Equals("udp://"))
+ {
+ play_control.auto_buffing_enable = 1;
+ play_control.buffing_min = 0.01; // default = 0.01
+ play_control.buffing_middle = 0.02; // default = 0.02
+ play_control.buffing_max = 0.20; // default = 0.80
+ play_control.byteiobufsize = 1024 * 128; // maps to av_open_input_file buffer size (1024 * 32)
+ //play_control.loopbufsize =;
+ //play_control.enable_rw_on_pause =;
+ }
+
m_aml_state.clear();
m_aml_state.push_back(0);
m_pid = m_dll->player_start(&play_control, 0);
@@ -1464,13 +1562,7 @@ void CAMLPlayer::Process()
// get our initial status.
GetStatus();
- // restore mute setting.
- SetMute(g_settings.m_bMute);
-
- // restore system volume setting.
- SetVolume(g_settings.m_fVolumeLevel);
-
- // the default staturation is to high, drop it
+ // the default staturation is too high, drop it
SetVideoSaturation(110);
// drop CGUIDialogBusy dialog and release the hold in OpenFile.
@@ -1576,13 +1668,14 @@ void CAMLPlayer::Process()
case PLAYER_EXIT:
if (m_log_level > 5)
{
- CLog::Log(LOGDEBUG, "CAMLPlayer::Process PLAYER_STOPED");
+ CLog::Log(LOGDEBUG, "CAMLPlayer::Process PLAYER_STOPPED");
CLog::Log(LOGDEBUG, "CAMLPlayer::Process: %s", m_dll->player_status2str(pstatus));
}
stopPlaying = true;
break;
}
- usleep(250 * 1000);
+ if (!stopPlaying)
+ usleep(250 * 1000);
}
}
}
@@ -1620,48 +1713,43 @@ void CAMLPlayer::Process()
if (m_log_level > 5)
CLog::Log(LOGDEBUG, "CAMLPlayer::Process exit");
}
-/*
-void CAMLPlayer::GetRenderFeatures(Features* renderFeatures)
+
+void CAMLPlayer::GetRenderFeatures(std::vector &renderFeatures)
{
- renderFeatures->push_back(RENDERFEATURE_ZOOM);
- renderFeatures->push_back(RENDERFEATURE_CONTRAST);
- renderFeatures->push_back(RENDERFEATURE_BRIGHTNESS);
- renderFeatures->push_back(RENDERFEATURE_STRETCH);
- return;
+ renderFeatures.push_back(RENDERFEATURE_ZOOM);
+ renderFeatures.push_back(RENDERFEATURE_CONTRAST);
+ renderFeatures.push_back(RENDERFEATURE_BRIGHTNESS);
+ renderFeatures.push_back(RENDERFEATURE_STRETCH);
}
-void CAMLPlayer::GetDeinterlaceMethods(Features* deinterlaceMethods)
+void CAMLPlayer::GetDeinterlaceMethods(std::vector &deinterlaceMethods)
{
- deinterlaceMethods->push_back(VS_INTERLACEMETHOD_DEINTERLACE);
- return;
+ deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
}
-void CAMLPlayer::GetDeinterlaceModes(Features* deinterlaceModes)
+void CAMLPlayer::GetDeinterlaceModes(std::vector &deinterlaceModes)
{
- deinterlaceModes->push_back(VS_DEINTERLACEMODE_AUTO);
- return;
+ deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
}
-void CAMLPlayer::GetScalingMethods(Features* scalingMethods)
+void CAMLPlayer::GetScalingMethods(std::vector &scalingMethods)
{
- return;
}
-void CAMLPlayer::GetAudioCapabilities(Features* audioCaps)
+void CAMLPlayer::GetAudioCapabilities(std::vector &audioCaps)
{
- audioCaps->push_back(IPC_AUD_OFFSET);
- audioCaps->push_back(IPC_AUD_SELECT_STREAM);
- return;
+ audioCaps.push_back(IPC_AUD_SELECT_STREAM);
+ audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
+ audioCaps.push_back(IPC_AUD_OFFSET);
}
-void CAMLPlayer::GetSubtitleCapabilities(Features* subCaps)
+void CAMLPlayer::GetSubtitleCapabilities(std::vector &subCaps)
{
- subCaps->push_back(IPC_SUBS_EXTERNAL);
- subCaps->push_back(IPC_SUBS_OFFSET);
- subCaps->push_back(IPC_SUBS_SELECT);
- return;
+ subCaps.push_back(IPC_SUBS_EXTERNAL);
+ subCaps.push_back(IPC_SUBS_SELECT);
+ subCaps.push_back(IPC_SUBS_OFFSET);
}
-*/
+
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
@@ -1795,8 +1883,8 @@ bool CAMLPlayer::WaitForStopped(int timeout_ms)
switch(pstatus)
{
default:
- usleep(100 * 1000);
- timeout_ms -= 100;
+ usleep(20 * 1000);
+ timeout_ms -= 20;
break;
case PLAYER_PLAYEND:
case PLAYER_STOPED:
@@ -1821,8 +1909,8 @@ bool CAMLPlayer::WaitForSearchOK(int timeout_ms)
switch(pstatus)
{
default:
- usleep(100 * 1000);
- timeout_ms -= 100;
+ usleep(20 * 1000);
+ timeout_ms -= 20;
break;
case PLAYER_STOPED:
return false;
@@ -1842,23 +1930,22 @@ bool CAMLPlayer::WaitForSearchOK(int timeout_ms)
bool CAMLPlayer::WaitForPlaying(int timeout_ms)
{
- // force the volume off in case we are starting muted
- m_audio_mute = true;
while (!m_bAbortRequest && (timeout_ms > 0))
{
-#if !defined(TARGET_ANDROID)
- // anoying that we have to hammer audio_set_volume
- // but have to catch it before any audio comes out.
- m_dll->audio_set_volume(m_pid, 0.0);
-#endif
+ // anoying that we have to hammer setting audio volume via mute
+ // but we have to catch it before any audio comes out.
+ // we cannot do this for m1 (playback will bork) so trap it out.
+ if (aml_get_cputype() != 1)
+ SetMute(m_audio_mute);
+
player_status pstatus = (player_status)GetPlayerSerializedState();
if (m_log_level > 5)
CLog::Log(LOGDEBUG, "CAMLPlayer::WaitForPlaying: %s", m_dll->player_status2str(pstatus));
switch(pstatus)
{
default:
- usleep(100 * 1000);
- timeout_ms -= 100;
+ usleep(20 * 1000);
+ timeout_ms -= 20;
break;
case PLAYER_ERROR:
case PLAYER_EXIT:
@@ -1866,6 +1953,8 @@ bool CAMLPlayer::WaitForPlaying(int timeout_ms)
return false;
break;
case PLAYER_RUNNING:
+ // restore mute/volume settings
+ SetMute(m_audio_mute);
return true;
break;
}
@@ -1884,8 +1973,8 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
switch(pstatus)
{
default:
- usleep(100 * 1000);
- timeout_ms -= 100;
+ usleep(20 * 1000);
+ timeout_ms -= 20;
break;
case PLAYER_ERROR:
case PLAYER_EXIT:
@@ -1896,35 +1985,50 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
ClearStreamInfos();
- media_info_t media_info;
+ media_info_t media_info = {{0}};
+#if defined(TARGET_ANDROID)
+ // media_info_t might be different so check its size.
+ // player_get_media_info will memset to zero the passed
+ // structure so alloc more space and preset to a know value
+ // so we can compare the size we use to the size the lib uses.
+ int msize = sizeof(media_info_t) + 10240;
+ media_info_t *test_media_info = (media_info_t*)calloc(msize, 1);
+ memset(test_media_info, 0xEF, msize);
+
+ int res = m_dll->player_get_media_info(m_pid, test_media_info);
+
+ uint8_t *t1 = (uint8_t*)test_media_info;
+ for (size_t i = msize-1; i >= 0; i--)
+ {
+ if (t1[i] != 0xEF)
+ {
+ if (sizeof(media_info_t) != i+1)
+ {
+ CLog::Log(LOGERROR, "CAMLPlayer::media_info_t(%d) size changed to %d",
+ sizeof(media_info_t), i+1);
+ // size is different, we cannot trust it
+ free(test_media_info);
+ return false;
+ }
+ break;
+ }
+ }
+ media_info = *test_media_info;
+ free(test_media_info);
+#else
int res = m_dll->player_get_media_info(m_pid, &media_info);
+#endif
if (res != PLAYER_SUCCESS)
return false;
if (m_log_level > 5)
- {
media_info_dump(&media_info);
- // m_video_index, m_audio_index, m_subtitle_index might be -1 eventhough
- // total_video_xxx is > 0, not sure why, they should be set to zero or
- // some other sensible value.
- CLog::Log(LOGDEBUG, "CAMLPlayer::WaitForFormatValid: "
- "m_video_index(%d), m_audio_index(%d), m_subtitle_index(%d), m_chapter_count(%d)",
- media_info.stream_info.cur_video_index,
- media_info.stream_info.cur_audio_index,
-#if !defined(TARGET_ANDROID)
- media_info.stream_info.cur_sub_index,
- media_info.stream_info.total_chapter_num);
-#else
- media_info.stream_info.cur_sub_index,
- 0);
-#endif
- }
-
// video info
if (media_info.stream_info.has_video && media_info.stream_info.total_video_num > 0)
{
- for (int i = 0; i < media_info.stream_info.total_video_num; i++)
+ for (int i = 0; i < media_info.stream_info.total_video_num &&
+ media_info.stream_info.total_video_num < MAX_VIDEO_STREAMS; i++)
{
AMLPlayerStreamInfo *info = new AMLPlayerStreamInfo;
info->Clear();
@@ -1961,7 +2065,8 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
// audio info
if (media_info.stream_info.has_audio && media_info.stream_info.total_audio_num > 0)
{
- for (int i = 0; i < media_info.stream_info.total_audio_num; i++)
+ for (int i = 0; i < media_info.stream_info.total_audio_num &&
+ media_info.stream_info.total_audio_num < MAX_AUDIO_STREAMS; i++)
{
AMLPlayerStreamInfo *info = new AMLPlayerStreamInfo;
info->Clear();
@@ -1973,10 +2078,11 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
info->bit_rate = media_info.audio_info[i]->bit_rate;
info->duration = media_info.audio_info[i]->duration;
info->format = media_info.audio_info[i]->aformat;
-#if !defined(TARGET_ANDROID)
+#if defined(HAS_AMLPLAYER_AUDIO_LANG)
if (media_info.audio_info[i]->audio_language[0] != 0)
info->language = std::string(media_info.audio_info[i]->audio_language, 3);
#endif
+
m_audio_streams.push_back(info);
}
@@ -1991,7 +2097,7 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
// subtitle info
if (media_info.stream_info.has_sub && media_info.stream_info.total_sub_num > 0)
{
- for (int i = 0; i < media_info.stream_info.total_sub_num; i++)
+ for (int i = 0; i < media_info.stream_info.total_sub_num && i < MAX_SUB_STREAMS; i++)
{
AMLPlayerStreamInfo *info = new AMLPlayerStreamInfo;
info->Clear();
@@ -2011,12 +2117,12 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
if (m_subtitle_count && m_subtitle_index != 0)
m_subtitle_index = 0;
-#if !defined(TARGET_ANDROID)
+#if defined(HAS_AMLPLAYER_CHAPTERS)
// chapter info
if (media_info.stream_info.total_chapter_num > 0)
{
m_chapter_count = media_info.stream_info.total_chapter_num;
- for (int i = 0; i < m_chapter_count; i++)
+ for (int i = 0; i < m_chapter_count && m_chapter_count < MAX_CHAPTERS; i++)
{
if (media_info.chapter_info[i] != NULL)
{
@@ -2029,6 +2135,7 @@ bool CAMLPlayer::WaitForFormatValid(int timeout_ms)
}
}
#endif
+
return true;
break;
}
@@ -2306,6 +2413,8 @@ void CAMLPlayer::SetVideoRect(const CRect &SrcRect, const CRect &DestRect)
char video_axis[256] = {0};
sprintf(video_axis, "%d %d %d %d", (int)dst_rect.x1, (int)dst_rect.y1, (int)dst_rect.x2, (int)dst_rect.y2);
aml_set_sysfs_str("/sys/class/video/axis", video_axis);
+ // make sure we are in 'full stretch' so we can stretch
+ aml_set_sysfs_int("/sys/class/video/screen_mode", 1);
/*
CStdString rectangle;
rectangle.Format("%i,%i,%i,%i",
@@ -2324,41 +2433,3 @@ void CAMLPlayer::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, con
player->SetVideoRect(SrcRect, DestRect);
}
-void CAMLPlayer::GetRenderFeatures(std::vector &renderFeatures)
-{
- renderFeatures.push_back(RENDERFEATURE_ZOOM);
- renderFeatures.push_back(RENDERFEATURE_CONTRAST);
- renderFeatures.push_back(RENDERFEATURE_BRIGHTNESS);
- renderFeatures.push_back(RENDERFEATURE_STRETCH);
-}
-
-void CAMLPlayer::GetDeinterlaceMethods(std::vector &deinterlaceMethods)
-{
- deinterlaceMethods.push_back(VS_INTERLACEMETHOD_DEINTERLACE);
-}
-
-void CAMLPlayer::GetDeinterlaceModes(std::vector &deinterlaceModes)
-{
- deinterlaceModes.push_back(VS_DEINTERLACEMODE_AUTO);
-}
-
-void CAMLPlayer::GetScalingMethods(std::vector &scalingMethods)
-{
-}
-
-void CAMLPlayer::GetAudioCapabilities(std::vector &audioCaps)
-{
- audioCaps.push_back(IPC_AUD_SELECT_STREAM);
- audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
-#if !defined(TARGET_ANDROID)
- audioCaps.push_back(IPC_AUD_OFFSET);
-#endif
-}
-
-void CAMLPlayer::GetSubtitleCapabilities(std::vector &subCaps)
-{
- subCaps.push_back(IPC_SUBS_EXTERNAL);
- subCaps.push_back(IPC_SUBS_SELECT);
- subCaps.push_back(IPC_SUBS_OFFSET);
-}
-
diff --git a/xbmc/cores/amlplayer/AMLPlayer.h b/xbmc/cores/amlplayer/AMLPlayer.h
index 2624b61efe784..d7aaec8a7774b 100644
--- a/xbmc/cores/amlplayer/AMLPlayer.h
+++ b/xbmc/cores/amlplayer/AMLPlayer.h
@@ -43,6 +43,7 @@ class CAMLSubTitleThread : public CThread
CAMLSubTitleThread(DllLibAmplayer* dll);
virtual ~CAMLSubTitleThread();
+ void Flush();
void UpdateSubtitle(CStdString &subtitle, int64_t elapsed_ms);
protected:
virtual void Process(void);
@@ -102,6 +103,7 @@ class CAMLPlayer : public IPlayer, public CThread
virtual int GetSubtitleCount();
virtual int GetSubtitle();
virtual void GetSubtitleName(int iStream, CStdString &strStreamName);
+ virtual void GetSubtitleLanguage(int iStream, CStdString &strStreamLang);
virtual void SetSubtitle(int iStream);
virtual bool GetSubtitleVisible();
virtual void SetSubtitleVisible(bool bVisible);
@@ -123,9 +125,9 @@ class CAMLPlayer : public IPlayer, public CThread
virtual int SeekChapter(int iChapter);
virtual float GetActualFPS();
- virtual void SeekTime(__int64 iTime = 0);
- virtual __int64 GetTime();
- virtual __int64 GetTotalTime();
+ virtual void SeekTime(int64_t iTime = 0);
+ virtual int64_t GetTime();
+ virtual int64_t GetTotalTime();
virtual int GetAudioBitrate();
virtual int GetVideoBitrate();
virtual int GetSourceBitrate();
@@ -158,14 +160,6 @@ class CAMLPlayer : public IPlayer, public CThread
virtual bool SetPlayerState(CStdString state) {return false;};
virtual CStdString GetPlayingTitle() {return "";};
-/*
- virtual void GetRenderFeatures(Features* renderFeatures);
- virtual void GetDeinterlaceMethods(Features* deinterlaceMethods);
- virtual void GetDeinterlaceModes(Features* deinterlaceModes);
- virtual void GetScalingMethods(Features* scalingMethods);
- virtual void GetAudioCapabilities(Features* audioCaps);
- virtual void GetSubtitleCapabilities(Features* subCaps);
-*/
virtual void GetRenderFeatures(std::vector &renderFeatures);
virtual void GetDeinterlaceMethods(std::vector &deinterlaceMethods);
@@ -244,7 +238,6 @@ class CAMLPlayer : public IPlayer, public CThread
CDVDPlayerSubtitle *m_dvdPlayerSubtitle;
CDVDOverlayContainer *m_dvdOverlayContainer;
- int m_chapter_index;
int m_chapter_count;
int m_show_mainvideo;
diff --git a/xbmc/cores/amlplayer/AMLUtils.cpp b/xbmc/cores/amlplayer/AMLUtils.cpp
deleted file mode 100644
index a127b33fa7ce3..0000000000000
--- a/xbmc/cores/amlplayer/AMLUtils.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2011-2012 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
- *
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-int aml_set_sysfs_str(const char *path, const char *val)
-{
- int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
- if (fd >= 0)
- {
- write(fd, val, strlen(val));
- close(fd);
- return 0;
- }
- return -1;
-}
-
-int aml_get_sysfs_str(const char *path, char *valstr, const int size)
-{
- int fd = open(path, O_RDONLY);
- if (fd >= 0)
- {
- read(fd, valstr, size - 1);
- valstr[strlen(valstr)] = '\0';
- close(fd);
- return 0;
- }
-
- sprintf(valstr, "%s", "fail");
- return -1;
-}
-
-int aml_set_sysfs_int(const char *path, const int val)
-{
- int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
- if (fd >= 0)
- {
- char bcmd[16];
- sprintf(bcmd, "%d", val);
- write(fd, bcmd, strlen(bcmd));
- close(fd);
- return 0;
- }
- return -1;
-}
-
-int aml_get_sysfs_int(const char *path)
-{
- int val = 0;
- int fd = open(path, O_RDONLY);
- if (fd >= 0)
- {
- char bcmd[16];
- read(fd, bcmd, sizeof(bcmd));
- val = strtol(bcmd, NULL, 16);
- close(fd);
- }
- return val;
-}
-
-bool aml_present()
-{
- static int has_aml = -1;
- if (has_aml == -1)
- {
- if (aml_get_sysfs_int("/sys/class/amhdmitx/amhdmitx0/disp_cap") != -1)
- has_aml = 1;
- else
- has_aml = 0;
- }
- return has_aml;
-}
-
-void aml_cpufreq_limit(bool limit)
-{
- static int audiotrack_cputype = -1;
- if (audiotrack_cputype == -1)
- {
- // defualt to m1 SoC
- audiotrack_cputype = 1;
-
- FILE *cpuinfo_fd = fopen("/proc/cpuinfo", "r");
- if (cpuinfo_fd)
- {
- char buffer[512];
- while (fgets(buffer, sizeof(buffer), cpuinfo_fd))
- {
- std::string stdbuffer(buffer);
- if (stdbuffer.find("MESON-M3") != std::string::npos)
- {
- audiotrack_cputype = 3;
- break;
- }
- }
- fclose(cpuinfo_fd);
- }
- }
- // On M1 SoCs, when playing hw decoded audio, we cannot drop below 600MHz
- // or risk hw audio dropouts. AML code does a 2X scaling based off
- // /sys/class/audiodsp/codec_mips but tests show that this is
- // seems risky so we just clamp to 600Mhz to be safe.
- if (audiotrack_cputype == 3)
- return;
-
- int cpufreq = 300000;
- if (limit)
- cpufreq = 600000;
-
- aml_set_sysfs_int("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", cpufreq);
-}
-
-void aml_set_audio_passthrough(bool passthrough)
-{
- if (aml_present())
- aml_set_sysfs_int("/sys/class/audiodsp/digital_raw", passthrough ? 1:0);
-}
diff --git a/xbmc/cores/amlplayer/DllLibamplayer.h b/xbmc/cores/amlplayer/DllLibamplayer.h
index 3bde96313d4bc..95f11647decca 100644
--- a/xbmc/cores/amlplayer/DllLibamplayer.h
+++ b/xbmc/cores/amlplayer/DllLibamplayer.h
@@ -25,6 +25,17 @@
extern "C"
{
+// beware, these will alter the structs
+// in player_type.h.
+#if 1
+ #define HAS_AMLPLAYER_CHAPTERS
+ #define HAS_AMLPLAYER_AUDIO_LANG
+ #define HAS_AMLPLAYER_AUDIO_SETDELAY
+ #define HAS_AMLPLAYER_AUDIO_SETVOLUME
+#else
+ #define HAS_AMLPLAYER_VIDEO_STREAMS10
+#endif
+
#include
#include
}
@@ -62,9 +73,13 @@ class DllLibAmplayerInterface
virtual int player_register_update_callback(callback_t *cb,update_state_fun_t up_fn,int interval_s)=0;
virtual char* player_status2str(player_status status)=0;
- virtual int audio_set_volume(int pid,float val)=0;
+#if defined(HAS_AMLPLAYER_AUDIO_SETDELAY)
virtual int audio_set_delay(int pid, int delay)=0;
-
+#endif
+#if defined(HAS_AMLPLAYER_AUDIO_SETVOLUME)
+ virtual int audio_set_volume(int pid,float val)=0;
+#endif
+
virtual int codec_open_sub_read(void)=0;
virtual int codec_close_sub_fd(int sub_fd)=0;
virtual int codec_get_sub_size_fd(int sub_fd)=0;
@@ -103,8 +118,12 @@ class DllLibAmplayer : public DllDynamic, DllLibAmplayerInterface
DEFINE_METHOD3(int, player_register_update_callback, (callback_t *p1, update_state_fun_t p2, int p3))
DEFINE_METHOD1(char*, player_status2str, (player_status p1))
- DEFINE_METHOD2(int, audio_set_volume, (int p1, float p2))
+#if defined(HAS_AMLPLAYER_AUDIO_SETDELAY)
DEFINE_METHOD2(int, audio_set_delay, (int p1, int p2))
+#endif
+#if defined(HAS_AMLPLAYER_AUDIO_SETVOLUME)
+ DEFINE_METHOD2(int, audio_set_volume, (int p1, float p2))
+#endif
DEFINE_METHOD0(int, codec_open_sub_read)
DEFINE_METHOD1(int, codec_close_sub_fd, (int p1))
@@ -140,8 +159,12 @@ class DllLibAmplayer : public DllDynamic, DllLibAmplayerInterface
RESOLVE_METHOD(player_register_update_callback)
RESOLVE_METHOD(player_status2str)
- RESOLVE_METHOD(audio_set_volume)
+#if defined(HAS_AMLPLAYER_AUDIO_SETDELAY)
RESOLVE_METHOD(audio_set_delay)
+#endif
+#if defined(HAS_AMLPLAYER_AUDIO_SETVOLUME)
+ RESOLVE_METHOD(audio_set_volume)
+#endif
RESOLVE_METHOD(codec_open_sub_read)
RESOLVE_METHOD(codec_close_sub_fd)
diff --git a/xbmc/cores/amlplayer/FileURLProtocol.cpp b/xbmc/cores/amlplayer/FileURLProtocol.cpp
index ba817b0372cd3..2a7a26dca03e6 100644
--- a/xbmc/cores/amlplayer/FileURLProtocol.cpp
+++ b/xbmc/cores/amlplayer/FileURLProtocol.cpp
@@ -56,6 +56,10 @@ int CFileURLProtocol::Open(AML_URLContext *h, const char *filename, int flags)
{
url = url.Right(url.size() - strlen("xb-"));
}
+ else if (url.Left(strlen("xb-sftp://")).Equals("xb-sftp://"))
+ {
+ url = url.Right(url.size() - strlen("xb-"));
+ }
else if (url.Left(strlen("xb-hdhomerun://")).Equals("xb-hdhomerun://"))
{
url = url.Right(url.size() - strlen("xb-"));
diff --git a/xbmc/cores/amlplayer/Makefile.in b/xbmc/cores/amlplayer/Makefile.in
index 3d16c3daebcf7..1645cf26c2e56 100644
--- a/xbmc/cores/amlplayer/Makefile.in
+++ b/xbmc/cores/amlplayer/Makefile.in
@@ -3,14 +3,14 @@
INCLUDES += -I$(prefix)/include/amlplayer
SRCS = AMLPlayer.cpp
-SRCS+= AMLUtils.cpp
SRCS+= FileURLProtocol.cpp
LIB = amlplayer.a
+ifneq (@USE_LIBAMCODEC@,1)
@abs_top_srcdir@/system/advancedsettings.xml: $(LIB)
cp -f amlplayer_advancedsettings.xml $@
+endif
include @abs_top_srcdir@/Makefile.include
-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
-
diff --git a/xbmc/cores/amlplayer/amlplayer_advancedsettings.xml b/xbmc/cores/amlplayer/amlplayer_advancedsettings.xml
index 7199cd47b68fc..310ff9589147d 100644
--- a/xbmc/cores/amlplayer/amlplayer_advancedsettings.xml
+++ b/xbmc/cores/amlplayer/amlplayer_advancedsettings.xml
@@ -1,6 +1,5 @@
diff --git a/xbmc/cores/dvdplayer/DVDClock.cpp b/xbmc/cores/dvdplayer/DVDClock.cpp
index 9eb744f170eb9..a523d5b2928b2 100644
--- a/xbmc/cores/dvdplayer/DVDClock.cpp
+++ b/xbmc/cores/dvdplayer/DVDClock.cpp
@@ -28,8 +28,8 @@
int64_t CDVDClock::m_systemOffset;
int64_t CDVDClock::m_systemFrequency;
CCriticalSection CDVDClock::m_systemsection;
-
bool CDVDClock::m_ismasterclock;
+CDVDClock *CDVDClock::m_playerclock = NULL;;
CDVDClock::CDVDClock()
{
@@ -45,10 +45,15 @@ CDVDClock::CDVDClock()
m_ismasterclock = true;
m_startClock = 0;
+
+ m_playerclock = this;
}
CDVDClock::~CDVDClock()
-{}
+{
+ CSingleLock lock(m_systemsection);
+ m_playerclock = NULL;
+}
// Returns the current absolute clock in units of DVD_TIME_BASE (usually microseconds).
double CDVDClock::GetAbsoluteClock(bool interpolated /*= true*/)
@@ -90,6 +95,12 @@ double CDVDClock::WaitAbsoluteClock(double target)
return (double)systemtarget / freq * DVD_TIME_BASE;
}
+CDVDClock* CDVDClock::GetMasterClock()
+{
+ CSingleLock lock(m_systemsection);
+ return m_playerclock;
+}
+
double CDVDClock::GetClock(bool interpolated /*= true*/)
{
CSharedLock lock(m_critSection);
diff --git a/xbmc/cores/dvdplayer/DVDClock.h b/xbmc/cores/dvdplayer/DVDClock.h
index dbf431b94d51a..27b9fc5385e41 100644
--- a/xbmc/cores/dvdplayer/DVDClock.h
+++ b/xbmc/cores/dvdplayer/DVDClock.h
@@ -66,7 +66,7 @@ class CDVDClock
//the rendermanager needs to know about that because it can synchronize the videoreferenceclock to the video timestamps
static void SetMasterClock(bool ismasterclock) { m_ismasterclock = ismasterclock; }
static bool IsMasterClock() { return m_ismasterclock; }
-
+ static CDVDClock* GetMasterClock();
protected:
static void CheckSystemClock();
static double SystemToAbsolute(int64_t system);
@@ -87,4 +87,5 @@ class CDVDClock
bool m_speedadjust;
CCriticalSection m_speedsection;
static bool m_ismasterclock;
+ static CDVDClock *m_playerclock;
};
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 0cea7a99c7e29..76891558e9b48 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -36,6 +36,9 @@
#if defined(HAVE_LIBCRYSTALHD)
#include "Video/DVDVideoCodecCrystalHD.h"
#endif
+#if defined(HAS_LIBAMCODEC)
+#include "Video/DVDVideoCodecAmlogic.h"
+#endif
#include "Audio/DVDAudioCodecFFmpeg.h"
#include "Audio/DVDAudioCodecLibMad.h"
#include "Audio/DVDAudioCodecPcm.h"
@@ -149,6 +152,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
#else
hwSupport += "CrystalHD:no ";
#endif
+#if defined(HAS_LIBAMCODEC)
+ hwSupport += "AMCodec:yes ";
+#else
+ hwSupport += "AMCodec:no ";
+#endif
#if defined(HAVE_LIBOPENMAX) && defined(_LINUX)
hwSupport += "OpenMax:yes ";
#elif defined(_LINUX)
@@ -171,12 +179,14 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
#endif
CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
-
+#if !defined(HAS_LIBAMCODEC)
// dvd's have weird still-frames in it, which is not fully supported in ffmpeg
if(hint.stills && (hint.codec == CODEC_ID_MPEG2VIDEO || hint.codec == CODEC_ID_MPEG1VIDEO))
{
if( (pCodec = OpenCodec(new CDVDVideoCodecLibMpeg2(), hint, options)) ) return pCodec;
}
+#endif
+
#if defined(HAVE_LIBVDADECODER)
if (!hint.software && g_guiSettings.GetBool("videoplayer.usevda"))
{
@@ -233,6 +243,14 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
}
#endif
+#if defined(HAS_LIBAMCODEC)
+ if (!hint.software /* && g_guiSettings.GetBool("videoplayer.useamcodec")*/)
+ {
+ CLog::Log(LOGINFO, "Amlogic Video Decoder...");
+ if ( (pCodec = OpenCodec(new CDVDVideoCodecAmlogic(), hint, options)) ) return pCodec;
+ }
+#endif
+
#if defined(HAVE_LIBOPENMAX)
if (g_guiSettings.GetBool("videoplayer.useomx") && !hint.software )
{
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp
new file mode 100644
index 0000000000000..c813e6b28bc13
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp
@@ -0,0 +1,2104 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#include "AMLCodec.h"
+#include "DynamicDll.h"
+
+#include "cores/dvdplayer/DVDClock.h"
+#include "cores/VideoRenderers/RenderManager.h"
+#include "settings/Settings.h"
+#include "utils/AMLUtils.h"
+#include "utils/log.h"
+#include "utils/TimeUtils.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// amcodec include
+extern "C" {
+#include
+} // extern "C"
+
+class DllLibamCodecInterface
+{
+public:
+ virtual ~DllLibamCodecInterface() {};
+
+ virtual int codec_init(codec_para_t *pcodec)=0;
+ virtual int codec_close(codec_para_t *pcodec)=0;
+ virtual int codec_reset(codec_para_t *pcodec)=0;
+ virtual int codec_pause(codec_para_t *pcodec)=0;
+ virtual int codec_resume(codec_para_t *pcodec)=0;
+ virtual int codec_write(codec_para_t *pcodec, void *buffer, int len)=0;
+ virtual int codec_checkin_pts(codec_para_t *pcodec, unsigned long pts)=0;
+ virtual int codec_get_vbuf_state(codec_para_t *pcodec, struct buf_status *)=0;
+
+ virtual int codec_init_cntl(codec_para_t *pcodec)=0;
+ virtual int codec_poll_cntl(codec_para_t *pcodec)=0;
+ virtual int codec_set_cntl_mode(codec_para_t *pcodec, unsigned int mode)=0;
+ virtual int codec_set_cntl_avthresh(codec_para_t *pcodec, unsigned int)=0;
+ virtual int codec_set_cntl_syncthresh(codec_para_t *pcodec, unsigned int syncthresh)=0;
+
+ // grab these from libamplayer
+ virtual int h263vld(unsigned char *inbuf, unsigned char *outbuf, int inbuf_len, int s263)=0;
+ virtual int decodeble_h263(unsigned char *buf)=0;
+
+ // grab this from amffmpeg so we do not have to load DllAvUtil
+ virtual AVRational av_d2q(double d, int max)=0;
+};
+
+class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface
+{
+ // libamcodec is static linked into libamplayer.so
+ DECLARE_DLL_WRAPPER(DllLibAmCodec, "libamplayer.so")
+
+ DEFINE_METHOD1(int, codec_init, (codec_para_t *p1))
+ DEFINE_METHOD1(int, codec_close, (codec_para_t *p1))
+ DEFINE_METHOD1(int, codec_reset, (codec_para_t *p1))
+ DEFINE_METHOD1(int, codec_pause, (codec_para_t *p1))
+ DEFINE_METHOD1(int, codec_resume, (codec_para_t *p1))
+ DEFINE_METHOD3(int, codec_write, (codec_para_t *p1, void *p2, int p3))
+ DEFINE_METHOD2(int, codec_checkin_pts, (codec_para_t *p1, unsigned long p2))
+ DEFINE_METHOD2(int, codec_get_vbuf_state, (codec_para_t *p1, struct buf_status * p2))
+
+ DEFINE_METHOD1(int, codec_init_cntl, (codec_para_t *p1))
+ DEFINE_METHOD1(int, codec_poll_cntl, (codec_para_t *p1))
+ DEFINE_METHOD2(int, codec_set_cntl_mode, (codec_para_t *p1, unsigned int p2))
+ DEFINE_METHOD2(int, codec_set_cntl_avthresh, (codec_para_t *p1, unsigned int p2))
+ DEFINE_METHOD2(int, codec_set_cntl_syncthresh,(codec_para_t *p1, unsigned int p2))
+
+ DEFINE_METHOD4(int, h263vld, (unsigned char *p1, unsigned char *p2, int p3, int p4))
+ DEFINE_METHOD1(int, decodeble_h263, (unsigned char *p1))
+
+ DEFINE_METHOD2(AVRational, av_d2q, (double p1, int p2))
+
+ BEGIN_METHOD_RESOLVE()
+ RESOLVE_METHOD(codec_init)
+ RESOLVE_METHOD(codec_close)
+ RESOLVE_METHOD(codec_reset)
+ RESOLVE_METHOD(codec_pause)
+ RESOLVE_METHOD(codec_resume)
+ RESOLVE_METHOD(codec_write)
+ RESOLVE_METHOD(codec_checkin_pts)
+ RESOLVE_METHOD(codec_get_vbuf_state)
+
+ RESOLVE_METHOD(codec_init_cntl)
+ RESOLVE_METHOD(codec_poll_cntl)
+ RESOLVE_METHOD(codec_set_cntl_mode)
+ RESOLVE_METHOD(codec_set_cntl_avthresh)
+ RESOLVE_METHOD(codec_set_cntl_syncthresh)
+
+ RESOLVE_METHOD(h263vld)
+ RESOLVE_METHOD(decodeble_h263)
+
+ RESOLVE_METHOD(av_d2q)
+ END_METHOD_RESOLVE()
+};
+
+//-----------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------
+// AppContext - Application state
+#define PTS_FREQ 90000
+#define UNIT_FREQ 96000
+#define AV_SYNC_THRESH PTS_FREQ*30
+
+#define TRICKMODE_NONE 0x00
+#define TRICKMODE_I 0x01
+#define TRICKMODE_FFFB 0x02
+
+// same as AV_NOPTS_VALUE
+#define INT64_0 INT64_C(0x8000000000000000)
+
+#define EXTERNAL_PTS (1)
+#define SYNC_OUTSIDE (2)
+
+// missing tags
+#define CODEC_TAG_VC_1 (0x312D4356)
+#define CODEC_TAG_RV30 (0x30335652)
+#define CODEC_TAG_RV40 (0x30345652)
+#define CODEC_TAG_MJPEG (0x47504a4d)
+#define CODEC_TAG_mjpeg (0x47504a4c)
+#define CODEC_TAG_jpeg (0x6765706a)
+#define CODEC_TAG_mjpa (0x61706a6d)
+
+#define RW_WAIT_TIME (20 * 1000) // 20ms
+
+#define P_PRE (0x02000000)
+#define F_PRE (0x03000000)
+#define PLAYER_SUCCESS (0)
+#define PLAYER_FAILED (-(P_PRE|0x01))
+#define PLAYER_NOMEM (-(P_PRE|0x02))
+#define PLAYER_EMPTY_P (-(P_PRE|0x03))
+
+#define PLAYER_WR_FAILED (-(P_PRE|0x21))
+#define PLAYER_WR_EMPTYP (-(P_PRE|0x22))
+#define PLAYER_WR_FINISH (P_PRE|0x1)
+
+#define PLAYER_PTS_ERROR (-(P_PRE|0x31))
+#define PLAYER_UNSUPPORT (-(P_PRE|0x35))
+#define PLAYER_CHECK_CODEC_ERROR (-(P_PRE|0x39))
+
+#define HDR_BUF_SIZE 1024
+typedef struct hdr_buf {
+ char *data;
+ int size;
+} hdr_buf_t;
+
+typedef struct am_packet {
+ AVPacket avpkt;
+ int64_t avpts;
+ int64_t avdts;
+ int avduration;
+ int isvalid;
+ int newflag;
+ int64_t lastpts;
+ unsigned char *data;
+ unsigned char *buf;
+ int data_size;
+ int buf_size;
+ hdr_buf_t *hdr;
+ codec_para_t *codec;
+} am_packet_t;
+
+typedef enum {
+ AM_STREAM_UNKNOWN = 0,
+ AM_STREAM_TS,
+ AM_STREAM_PS,
+ AM_STREAM_ES,
+ AM_STREAM_RM,
+ AM_STREAM_AUDIO,
+ AM_STREAM_VIDEO,
+} pstream_type;
+
+typedef union {
+ int64_t total_bytes;
+ unsigned int vpkt_num;
+ unsigned int spkt_num;
+} read_write_size;
+
+typedef struct {
+ unsigned int read_end_flag: 1;
+ unsigned int end_flag: 1;
+ unsigned int reset_flag: 1;
+ int check_lowlevel_eagain_cnt;
+} p_ctrl_info_t;
+
+typedef struct am_private_t
+{
+ am_packet_t am_pkt;
+ codec_para_t vcodec;
+
+ pstream_type stream_type;
+ p_ctrl_info_t playctrl_info;
+
+ read_write_size read_size;
+ read_write_size write_size;
+ int check_first_pts;
+
+ vformat_t video_format;
+ int video_pid;
+ unsigned int video_codec_id;
+ unsigned int video_codec_tag;
+ vdec_type_t video_codec_type;
+ unsigned int video_width;
+ unsigned int video_height;
+ unsigned int video_ratio;
+ unsigned int video_ratio64;
+ unsigned int video_rate;
+ unsigned int video_rotation_degree;
+ int flv_flag;
+ int h263_decodable;
+ int extrasize;
+ uint8_t *extradata;
+ DllLibAmCodec *m_dll;
+} am_private_t;
+
+/*************************************************************************/
+static int64_t get_pts_video()
+{
+ int fd = open("/sys/class/tsync/pts_video", O_RDONLY);
+ if (fd >= 0)
+ {
+ char pts_str[16];
+ int size = read(fd, pts_str, sizeof(pts_str));
+ close(fd);
+ if (size > 0)
+ {
+ unsigned long pts = strtoul(pts_str, NULL, 16);
+ return pts;
+ }
+ }
+
+ CLog::Log(LOGERROR, "get_pts_video: open /tsync/event error");
+ return -1;
+}
+
+static int set_pts_pcrscr(int64_t value)
+{
+ int fd = open("/sys/class/tsync/pts_pcrscr", O_WRONLY);
+ if (fd >= 0)
+ {
+ char pts_str[64];
+ unsigned long pts = (unsigned long)value;
+ sprintf(pts_str, "0x%lx", pts);
+ write(fd, pts_str, strlen(pts_str));
+ close(fd);
+ return 0;
+ }
+
+ CLog::Log(LOGERROR, "set_pts_pcrscr: open pts_pcrscr error");
+ return -1;
+}
+
+static vformat_t codecid_to_vformat(enum CodecID id)
+{
+ vformat_t format;
+ switch (id)
+ {
+ case CODEC_ID_MPEG1VIDEO:
+ case CODEC_ID_MPEG2VIDEO:
+ case CODEC_ID_MPEG2VIDEO_XVMC:
+ format = VFORMAT_MPEG12;
+ break;
+ case CODEC_ID_H263:
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_H263P:
+ case CODEC_ID_H263I:
+ case CODEC_ID_MSMPEG4V2:
+ case CODEC_ID_MSMPEG4V3:
+ case CODEC_ID_FLV1:
+ format = VFORMAT_MPEG4;
+ break;
+ case CODEC_ID_RV10:
+ case CODEC_ID_RV20:
+ case CODEC_ID_RV30:
+ case CODEC_ID_RV40:
+ format = VFORMAT_REAL;
+ break;
+ case CODEC_ID_H264:
+ format = VFORMAT_H264;
+ break;
+ /*
+ case CODEC_ID_H264MVC:
+ // H264 Multiview Video Coding (3d blurays)
+ format = VFORMAT_H264MVC;
+ break;
+ */
+ case CODEC_ID_MJPEG:
+ format = VFORMAT_MJPEG;
+ break;
+ case CODEC_ID_VC1:
+ case CODEC_ID_WMV3:
+ format = VFORMAT_VC1;
+ break;
+ case CODEC_ID_AVS:
+ case CODEC_ID_CAVS:
+ format = VFORMAT_AVS;
+ break;
+
+ default:
+ format = VFORMAT_UNSUPPORT;
+ break;
+ }
+
+ CLog::Log(LOGDEBUG, "codecid_to_vformat, id(%d) -> vformat(%d)", (int)id, format);
+ return format;
+}
+
+static vdec_type_t codec_tag_to_vdec_type(unsigned int codec_tag)
+{
+ vdec_type_t dec_type;
+ switch (codec_tag)
+ {
+ case CODEC_TAG_MJPEG:
+ case CODEC_TAG_mjpeg:
+ case CODEC_TAG_jpeg:
+ case CODEC_TAG_mjpa:
+ dec_type = VIDEO_DEC_FORMAT_MJPEG;
+ break;
+ case CODEC_TAG_XVID:
+ case CODEC_TAG_xvid:
+ case CODEC_TAG_XVIX:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+ break;
+ case CODEC_TAG_COL1:
+ case CODEC_TAG_DIV3:
+ case CODEC_TAG_MP43:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_3;
+ break;
+ case CODEC_TAG_DIV4:
+ case CODEC_TAG_DIVX:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_4;
+ break;
+ case CODEC_TAG_DIV5:
+ case CODEC_TAG_DX50:
+ case CODEC_TAG_M4S2:
+ case CODEC_TAG_FMP4:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+ break;
+ case CODEC_TAG_DIV6:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+ break;
+ case CODEC_TAG_MP4V:
+ case CODEC_TAG_RMP4:
+ case CODEC_TAG_MPG4:
+ case CODEC_TAG_mp4v:
+ case CODEC_ID_MPEG4:
+ dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+ break;
+ case CODEC_ID_H263:
+ case CODEC_TAG_H263:
+ case CODEC_TAG_h263:
+ case CODEC_TAG_s263:
+ case CODEC_TAG_F263:
+ dec_type = VIDEO_DEC_FORMAT_H263;
+ break;
+ case CODEC_TAG_AVC1:
+ case CODEC_TAG_avc1:
+ case CODEC_TAG_H264:
+ case CODEC_TAG_h264:
+ dec_type = VIDEO_DEC_FORMAT_H264;
+ break;
+ case CODEC_ID_RV30:
+ case CODEC_TAG_RV30:
+ dec_type = VIDEO_DEC_FORMAT_REAL_8;
+ break;
+ case CODEC_ID_RV40:
+ case CODEC_TAG_RV40:
+ dec_type = VIDEO_DEC_FORMAT_REAL_9;
+ break;
+ case CODEC_ID_H264:
+ dec_type = VIDEO_DEC_FORMAT_H264;
+ break;
+ /*
+ case CODEC_ID_H264MVC:
+ dec_type = VIDEO_DEC_FORMAT_H264;
+ break;
+ */
+ case CODEC_TAG_WMV3:
+ dec_type = VIDEO_DEC_FORMAT_WMV3;
+ break;
+ case CODEC_ID_VC1:
+ case CODEC_TAG_VC_1:
+ case CODEC_TAG_WVC1:
+ case CODEC_TAG_WMVA:
+ dec_type = VIDEO_DEC_FORMAT_WVC1;
+ break;
+ case CODEC_ID_VP6F:
+ dec_type = VIDEO_DEC_FORMAT_SW;
+ break;
+ default:
+ dec_type = VIDEO_DEC_FORMAT_UNKNOW;
+ break;
+ }
+
+ CLog::Log(LOGDEBUG, "codec_tag_to_vdec_type, codec_tag(%d) -> vdec_type(%d)", codec_tag, dec_type);
+ return dec_type;
+}
+
+static void am_packet_init(am_packet_t *pkt)
+{
+ memset(&pkt->avpkt, 0, sizeof(AVPacket));
+ pkt->avpts = 0;
+ pkt->avdts = 0;
+ pkt->avduration = 0;
+ pkt->isvalid = 0;
+ pkt->newflag = 0;
+ pkt->lastpts = 0;
+ pkt->data = NULL;
+ pkt->buf = NULL;
+ pkt->data_size = 0;
+ pkt->buf_size = 0;
+ pkt->hdr = NULL;
+ pkt->codec = NULL;
+}
+
+void am_packet_release(am_packet_t *pkt)
+{
+ if (pkt->buf != NULL)
+ {
+ free(pkt->buf);
+ pkt->buf= NULL;
+ }
+ if (pkt->hdr != NULL)
+ {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ free(pkt->hdr);
+ pkt->hdr = NULL;
+ }
+ pkt->codec = NULL;
+}
+
+int check_in_pts(am_private_t *para, am_packet_t *pkt)
+{
+ int last_duration = 0;
+ static int last_v_duration = 0;
+ int64_t pts = 0;
+
+ last_duration = last_v_duration;
+
+ if (para->stream_type == AM_STREAM_ES) {
+ if ((int64_t)INT64_0 != pkt->avpts) {
+ pts = pkt->avpts;
+
+ if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) {
+ CLog::Log(LOGDEBUG, "ERROR check in pts error!");
+ return PLAYER_PTS_ERROR;
+ }
+
+ } else if ((int64_t)INT64_0 != pkt->avdts) {
+ pts = pkt->avdts * last_duration;
+
+ if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) {
+ CLog::Log(LOGDEBUG, "ERROR check in dts error!");
+ return PLAYER_PTS_ERROR;
+ }
+
+ last_v_duration = pkt->avduration ? pkt->avduration : 1;
+ } else {
+ if (!para->check_first_pts) {
+ if (para->m_dll->codec_checkin_pts(pkt->codec, 0) != 0) {
+ CLog::Log(LOGDEBUG, "ERROR check in 0 to video pts error!");
+ return PLAYER_PTS_ERROR;
+ }
+ }
+ }
+ if (!para->check_first_pts) {
+ para->check_first_pts = 1;
+ }
+ }
+ if (pts > 0)
+ pkt->lastpts = pts;
+
+ return PLAYER_SUCCESS;
+}
+
+static int check_write_finish(am_private_t *para, am_packet_t *pkt)
+{
+ if (para->playctrl_info.read_end_flag) {
+ if ((para->write_size.vpkt_num == para->read_size.vpkt_num)) {
+ return PLAYER_WR_FINISH;
+ }
+ }
+ return PLAYER_WR_FAILED;
+}
+
+static int write_header(am_private_t *para, am_packet_t *pkt)
+{
+ int write_bytes = 0, len = 0;
+
+ if (pkt->hdr && pkt->hdr->size > 0) {
+ if ((NULL == pkt->codec) || (NULL == pkt->hdr->data)) {
+ CLog::Log(LOGDEBUG, "[write_header]codec null!");
+ return PLAYER_EMPTY_P;
+ }
+ //some wvc1 es data not need to add header
+ if (para->video_format == VFORMAT_VC1 && para->video_codec_type == VIDEO_DEC_FORMAT_WVC1) {
+ if ((pkt->data) && (pkt->data_size >= 4)
+ && (pkt->data[0] == 0) && (pkt->data[1] == 0)
+ && (pkt->data[2] == 1) && (pkt->data[3] == 0xd || pkt->data[3] == 0xf)) {
+ return PLAYER_SUCCESS;
+ }
+ }
+ while (1) {
+ write_bytes = para->m_dll->codec_write(pkt->codec, pkt->hdr->data + len, pkt->hdr->size - len);
+ if (write_bytes < 0 || write_bytes > (pkt->hdr->size - len)) {
+ if (-errno != AVERROR(EAGAIN)) {
+ CLog::Log(LOGDEBUG, "ERROR:write header failed!");
+ return PLAYER_WR_FAILED;
+ } else {
+ continue;
+ }
+ } else {
+ len += write_bytes;
+ if (len == pkt->hdr->size) {
+ break;
+ }
+ }
+ }
+ }
+ return PLAYER_SUCCESS;
+}
+
+int check_avbuffer_enough(am_private_t *para, am_packet_t *pkt)
+{
+ return 1;
+}
+
+int write_av_packet(am_private_t *para, am_packet_t *pkt)
+{
+ //CLog::Log(LOGDEBUG, "write_av_packet, pkt->isvalid(%d), pkt->data(%p), pkt->data_size(%d)",
+ // pkt->isvalid, pkt->data, pkt->data_size);
+
+ int write_bytes = 0, len = 0, ret;
+ unsigned char *buf;
+ int size;
+
+ if (pkt->newflag) {
+ if (pkt->isvalid) {
+ ret = check_in_pts(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ CLog::Log(LOGDEBUG, "check in pts failed");
+ return PLAYER_WR_FAILED;
+ }
+ }
+ if (write_header(para, pkt) == PLAYER_WR_FAILED) {
+ CLog::Log(LOGDEBUG, "[%s]write header failed!", __FUNCTION__);
+ return PLAYER_WR_FAILED;
+ }
+ pkt->newflag = 0;
+ }
+
+ buf = pkt->data;
+ size = pkt->data_size ;
+ if (size == 0 && pkt->isvalid) {
+ para->write_size.vpkt_num++;
+ pkt->isvalid = 0;
+ }
+ while (size > 0 && pkt->isvalid) {
+ write_bytes = para->m_dll->codec_write(pkt->codec, (char *)buf, size);
+ if (write_bytes < 0 || write_bytes > size) {
+ if (-errno != AVERROR(EAGAIN)) {
+ para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+ CLog::Log(LOGDEBUG, "write codec data failed!");
+ return PLAYER_WR_FAILED;
+ } else {
+ // EAGAIN to see if buffer full or write time out too much
+ if (check_avbuffer_enough(para, pkt)) {
+ para->playctrl_info.check_lowlevel_eagain_cnt++;
+ } else {
+ para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+ }
+
+ if (para->playctrl_info.check_lowlevel_eagain_cnt > 50) {
+ // reset decoder
+ para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+ para->playctrl_info.reset_flag = 1;
+ para->playctrl_info.end_flag = 1;
+ CLog::Log(LOGDEBUG, "$$$$$$ write blocked, need reset decoder!$$$$$$");
+ }
+ //pkt->data += len;
+ //pkt->data_size -= len;
+ usleep(RW_WAIT_TIME);
+ CLog::Log(LOGDEBUG, "usleep(RW_WAIT_TIME), len(%d)", len);
+ return PLAYER_SUCCESS;
+ }
+ } else {
+ para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+ len += write_bytes;
+ if (len == pkt->data_size) {
+ para->write_size.vpkt_num++;
+ pkt->isvalid = 0;
+ pkt->data_size = 0;
+ break;
+ } else if (len < pkt->data_size) {
+ buf += write_bytes;
+ size -= write_bytes;
+ } else {
+ return PLAYER_WR_FAILED;
+ }
+ }
+ }
+ if (check_write_finish(para, pkt) == PLAYER_WR_FINISH) {
+ return PLAYER_WR_FINISH;
+ }
+ return PLAYER_SUCCESS;
+}
+
+static int check_size_in_buffer(unsigned char *p, int len)
+{
+ unsigned int size;
+ unsigned char *q = p;
+ while ((q + 4) < (p + len)) {
+ size = (*q << 24) | (*(q + 1) << 16) | (*(q + 2) << 8) | (*(q + 3));
+ if (size & 0xff000000) {
+ return 0;
+ }
+
+ if (q + size + 4 == p + len) {
+ return 1;
+ }
+
+ q += size + 4;
+ }
+ return 0;
+}
+
+static int check_size_in_buffer3(unsigned char *p, int len)
+{
+ unsigned int size;
+ unsigned char *q = p;
+ while ((q + 3) < (p + len)) {
+ size = (*q << 16) | (*(q + 1) << 8) | (*(q + 2));
+
+ if (q + size + 3 == p + len) {
+ return 1;
+ }
+
+ q += size + 3;
+ }
+ return 0;
+}
+
+static int check_size_in_buffer2(unsigned char *p, int len)
+{
+ unsigned int size;
+ unsigned char *q = p;
+ while ((q + 2) < (p + len)) {
+ size = (*q << 8) | (*(q + 1));
+
+ if (q + size + 2 == p + len) {
+ return 1;
+ }
+
+ q += size + 2;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+static int m4s2_dx50_mp4v_add_header(unsigned char *buf, int size, am_packet_t *pkt)
+{
+ if (size > pkt->hdr->size) {
+ free(pkt->hdr->data), pkt->hdr->data = NULL;
+ pkt->hdr->size = 0;
+
+ pkt->hdr->data = (char*)malloc(size);
+ if (!pkt->hdr->data) {
+ CLog::Log(LOGDEBUG, "[m4s2_dx50_add_header] NOMEM!");
+ return PLAYER_FAILED;
+ }
+ }
+
+ pkt->hdr->size = size;
+ memcpy(pkt->hdr->data, buf, size);
+
+ return PLAYER_SUCCESS;
+}
+
+static int m4s2_dx50_mp4v_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ CLog::Log(LOGDEBUG, "m4s2_dx50_mp4v_write_header");
+ int ret = m4s2_dx50_mp4v_add_header(para->extradata, para->extrasize, pkt);
+ if (ret == PLAYER_SUCCESS) {
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[m4s2_dx50_mp4v_add_header]invalid video codec!");
+ return PLAYER_EMPTY_P;
+ }
+ pkt->newflag = 1;
+ ret = write_av_packet(para, pkt);
+ }
+ return ret;
+}
+
+static int mjpeg_data_prefeeding(am_packet_t *pkt)
+{
+ const unsigned char mjpeg_addon_data[] = {
+ 0xff, 0xd8, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10,
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
+ 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
+ 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
+ 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+ 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4,
+ 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01,
+ 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+ 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24,
+ 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+ };
+
+ if (pkt->hdr->data) {
+ memcpy(pkt->hdr->data, &mjpeg_addon_data, sizeof(mjpeg_addon_data));
+ pkt->hdr->size = sizeof(mjpeg_addon_data);
+ } else {
+ CLog::Log(LOGDEBUG, "[mjpeg_data_prefeeding]No enough memory!");
+ return PLAYER_FAILED;
+ }
+ return PLAYER_SUCCESS;
+}
+
+static int mjpeg_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ mjpeg_data_prefeeding(pkt);
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[mjpeg_write_header]invalid codec!");
+ return PLAYER_EMPTY_P;
+ }
+ pkt->newflag = 1;
+ write_av_packet(para, pkt);
+ return PLAYER_SUCCESS;
+}
+
+static int divx3_data_prefeeding(am_packet_t *pkt, unsigned w, unsigned h)
+{
+ unsigned i = (w << 12) | (h & 0xfff);
+ unsigned char divx311_add[10] = {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+ };
+ divx311_add[5] = (i >> 16) & 0xff;
+ divx311_add[6] = (i >> 8) & 0xff;
+ divx311_add[7] = i & 0xff;
+
+ if (pkt->hdr->data) {
+ memcpy(pkt->hdr->data, divx311_add, sizeof(divx311_add));
+ pkt->hdr->size = sizeof(divx311_add);
+ } else {
+ CLog::Log(LOGDEBUG, "[divx3_data_prefeeding]No enough memory!");
+ return PLAYER_FAILED;
+ }
+ return PLAYER_SUCCESS;
+}
+
+static int divx3_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ CLog::Log(LOGDEBUG, "divx3_write_header");
+ divx3_data_prefeeding(pkt, para->video_width, para->video_height);
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[divx3_write_header]invalid codec!");
+ return PLAYER_EMPTY_P;
+ }
+ pkt->newflag = 1;
+ write_av_packet(para, pkt);
+ return PLAYER_SUCCESS;
+}
+
+static int h264_add_header(unsigned char *buf, int size, am_packet_t *pkt)
+{
+ char nal_start_code[] = {0x0, 0x0, 0x0, 0x1};
+ int nalsize;
+ unsigned char* p;
+ int tmpi;
+ unsigned char* extradata = buf;
+ int header_len = 0;
+ char* buffer = pkt->hdr->data;
+
+ p = extradata;
+
+ // h264 annex-b
+ if ((p[0]==0 && p[1]==0 && p[2]==0 && p[3]==1) && size < HDR_BUF_SIZE) {
+ CLog::Log(LOGDEBUG, "add 264 header in stream before header len=%d",size);
+ memcpy(buffer, buf, size);
+ pkt->hdr->size = size;
+ return PLAYER_SUCCESS;
+ }
+
+ if (size < 4) {
+ return PLAYER_FAILED;
+ }
+
+ if (size < 10) {
+ CLog::Log(LOGDEBUG, "avcC too short");
+ return PLAYER_FAILED;
+ }
+
+ // h264 avcC
+ if (*p != 1) {
+ CLog::Log(LOGDEBUG, "Unknown avcC version %d", *p);
+ return PLAYER_FAILED;
+ }
+
+ int cnt = *(p + 5) & 0x1f; //number of sps
+ // CLog::Log(LOGDEBUG, "number of sps :%d", cnt);
+ p += 6;
+ for (tmpi = 0; tmpi < cnt; tmpi++) {
+ nalsize = (*p << 8) | (*(p + 1));
+ memcpy(&(buffer[header_len]), nal_start_code, 4);
+ header_len += 4;
+ memcpy(&(buffer[header_len]), p + 2, nalsize);
+ header_len += nalsize;
+ p += (nalsize + 2);
+ }
+
+ cnt = *(p++); //Number of pps
+ // CLog::Log(LOGDEBUG, "number of pps :%d", cnt);
+ for (tmpi = 0; tmpi < cnt; tmpi++) {
+ nalsize = (*p << 8) | (*(p + 1));
+ memcpy(&(buffer[header_len]), nal_start_code, 4);
+ header_len += 4;
+ memcpy(&(buffer[header_len]), p + 2, nalsize);
+ header_len += nalsize;
+ p += (nalsize + 2);
+ }
+ if (header_len >= HDR_BUF_SIZE) {
+ CLog::Log(LOGDEBUG, "header_len %d is larger than max length", header_len);
+ return 0;
+ }
+ pkt->hdr->size = header_len;
+
+ return PLAYER_SUCCESS;
+}
+static int h264_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ // CLog::Log(LOGDEBUG, "h264_write_header");
+ int ret = -1;
+
+ ret = h264_add_header(para->extradata, para->extrasize, pkt);
+ if (ret == PLAYER_SUCCESS) {
+ //if (ctx->vcodec) {
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ //CLog::Log(LOGDEBUG, "[pre_header_feeding]invalid video codec!");
+ return PLAYER_EMPTY_P;
+ }
+
+ pkt->newflag = 1;
+ ret = write_av_packet(para, pkt);
+ }
+ return ret;
+}
+
+static int wmv3_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ CLog::Log(LOGDEBUG, "wmv3_write_header");
+ unsigned i, check_sum = 0;
+ unsigned data_len = para->extrasize + 4;
+
+ pkt->hdr->data[0] = 0;
+ pkt->hdr->data[1] = 0;
+ pkt->hdr->data[2] = 1;
+ pkt->hdr->data[3] = 0x10;
+
+ pkt->hdr->data[4] = 0;
+ pkt->hdr->data[5] = (data_len >> 16) & 0xff;
+ pkt->hdr->data[6] = 0x88;
+ pkt->hdr->data[7] = (data_len >> 8) & 0xff;
+ pkt->hdr->data[8] = data_len & 0xff;
+ pkt->hdr->data[9] = 0x88;
+
+ pkt->hdr->data[10] = 0xff;
+ pkt->hdr->data[11] = 0xff;
+ pkt->hdr->data[12] = 0x88;
+ pkt->hdr->data[13] = 0xff;
+ pkt->hdr->data[14] = 0xff;
+ pkt->hdr->data[15] = 0x88;
+
+ for (i = 4 ; i < 16 ; i++) {
+ check_sum += pkt->hdr->data[i];
+ }
+
+ pkt->hdr->data[16] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[17] = check_sum & 0xff;
+ pkt->hdr->data[18] = 0x88;
+ pkt->hdr->data[19] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[20] = check_sum & 0xff;
+ pkt->hdr->data[21] = 0x88;
+
+ pkt->hdr->data[22] = (para->video_width >> 8) & 0xff;
+ pkt->hdr->data[23] = para->video_width & 0xff;
+ pkt->hdr->data[24] = (para->video_height >> 8) & 0xff;
+ pkt->hdr->data[25] = para->video_height & 0xff;
+
+ memcpy(pkt->hdr->data + 26, para->extradata, para->extrasize);
+ pkt->hdr->size = para->extrasize + 26;
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[wmv3_write_header]invalid codec!");
+ return PLAYER_EMPTY_P;
+ }
+ pkt->newflag = 1;
+ return write_av_packet(para, pkt);
+}
+
+static int wvc1_write_header(am_private_t *para, am_packet_t *pkt)
+{
+ CLog::Log(LOGDEBUG, "wvc1_write_header");
+ memcpy(pkt->hdr->data, para->extradata + 1, para->extrasize - 1);
+ pkt->hdr->size = para->extrasize - 1;
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[wvc1_write_header]invalid codec!");
+ return PLAYER_EMPTY_P;
+ }
+ pkt->newflag = 1;
+ return write_av_packet(para, pkt);
+}
+
+static int mpeg_add_header(am_private_t *para, am_packet_t *pkt)
+{
+ CLog::Log(LOGDEBUG, "mpeg_add_header");
+#define STUFF_BYTES_LENGTH (256)
+ int size;
+ unsigned char packet_wrapper[] = {
+ 0x00, 0x00, 0x01, 0xe0,
+ 0x00, 0x00, /* pes packet length */
+ 0x81, 0xc0, 0x0d,
+ 0x20, 0x00, 0x00, 0x00, 0x00, /* PTS */
+ 0x1f, 0xff, 0xff, 0xff, 0xff, /* DTS */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ size = para->extrasize + sizeof(packet_wrapper);
+ packet_wrapper[4] = size >> 8 ;
+ packet_wrapper[5] = size & 0xff ;
+ memcpy(pkt->hdr->data, packet_wrapper, sizeof(packet_wrapper));
+ size = sizeof(packet_wrapper);
+ //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]wrapper size=%d\n",__LINE__,size);
+ memcpy(pkt->hdr->data + size, para->extradata, para->extrasize);
+ size += para->extrasize;
+ //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]wrapper+seq size=%d\n",__LINE__,size);
+ memset(pkt->hdr->data + size, 0xff, STUFF_BYTES_LENGTH);
+ size += STUFF_BYTES_LENGTH;
+ pkt->hdr->size = size;
+ //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]hdr_size=%d\n",__LINE__,size);
+ if (1) {
+ pkt->codec = ¶->vcodec;
+ } else {
+ CLog::Log(LOGDEBUG, "[mpeg_add_header]invalid codec!");
+ return PLAYER_EMPTY_P;
+ }
+
+ pkt->newflag = 1;
+ return write_av_packet(para, pkt);
+}
+
+int pre_header_feeding(am_private_t *para, am_packet_t *pkt)
+{
+ int ret;
+ if (para->stream_type == AM_STREAM_ES) {
+ if (pkt->hdr == NULL) {
+ pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+ pkt->hdr->data = (char *)malloc(HDR_BUF_SIZE);
+ if (!pkt->hdr->data) {
+ //CLog::Log(LOGDEBUG, "[pre_header_feeding] NOMEM!");
+ return PLAYER_NOMEM;
+ }
+ }
+
+ if (VFORMAT_H264 == para->video_format /*|| VFORMAT_H264MVC == para->video_format*/) {
+ ret = h264_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ } else if ((VFORMAT_MPEG4 == para->video_format) && (VIDEO_DEC_FORMAT_MPEG4_3 == para->video_codec_type)) {
+ ret = divx3_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ } else if ((CODEC_TAG_M4S2 == para->video_codec_tag)
+ || (CODEC_TAG_DX50 == para->video_codec_tag)
+ || (CODEC_TAG_mp4v == para->video_codec_tag)) {
+ ret = m4s2_dx50_mp4v_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ /*
+ } else if ((AVI_FILE == para->file_type)
+ && (VIDEO_DEC_FORMAT_MPEG4_3 != para->vstream_info.video_codec_type)
+ && (VFORMAT_H264 != para->vstream_info.video_format)
+ && (VFORMAT_VC1 != para->vstream_info.video_format)) {
+ ret = avi_write_header(para);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ */
+ } else if (CODEC_TAG_WMV3 == para->video_codec_tag) {
+ CLog::Log(LOGDEBUG, "CODEC_TAG_WMV3 == para->video_codec_tag");
+ ret = wmv3_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ } else if ((CODEC_TAG_WVC1 == para->video_codec_tag)
+ || (CODEC_TAG_VC_1 == para->video_codec_tag)
+ || (CODEC_TAG_WMVA == para->video_codec_tag)) {
+ CLog::Log(LOGDEBUG, "CODEC_TAG_WVC1 == para->video_codec_tag");
+ ret = wvc1_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ /*
+ } else if ((MKV_FILE == para->file_type) &&
+ ((VFORMAT_MPEG4 == para->vstream_info.video_format)
+ || (VFORMAT_MPEG12 == para->vstream_info.video_format))) {
+ ret = mkv_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ */
+ } else if (VFORMAT_MJPEG == para->video_format) {
+ ret = mjpeg_write_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ }
+
+ if (pkt->hdr) {
+ if (pkt->hdr->data) {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ }
+ free(pkt->hdr);
+ pkt->hdr = NULL;
+ }
+ }
+ else if (para->stream_type == AM_STREAM_PS) {
+ if (pkt->hdr == NULL) {
+ pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+ pkt->hdr->data = (char*)malloc(HDR_BUF_SIZE);
+ if (!pkt->hdr->data) {
+ CLog::Log(LOGDEBUG, "[pre_header_feeding] NOMEM!");
+ return PLAYER_NOMEM;
+ }
+ }
+ if (( CODEC_ID_MPEG1VIDEO == para->video_codec_id)
+ || (CODEC_ID_MPEG2VIDEO == para->video_codec_id)
+ || (CODEC_ID_MPEG2VIDEO_XVMC == para->video_codec_id)) {
+ ret = mpeg_add_header(para, pkt);
+ if (ret != PLAYER_SUCCESS) {
+ return ret;
+ }
+ }
+ if (pkt->hdr) {
+ if (pkt->hdr->data) {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ }
+ free(pkt->hdr);
+ pkt->hdr = NULL;
+ }
+ }
+ return PLAYER_SUCCESS;
+}
+
+/*************************************************************************/
+int h264_update_frame_header(am_packet_t *pkt)
+{
+ int nalsize, size = pkt->data_size;
+ unsigned char *data = pkt->data;
+ unsigned char *p = data;
+ if (p != NULL) {
+ if (check_size_in_buffer(p, size)) {
+ while ((p + 4) < (data + size)) {
+ nalsize = (*p << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | (*(p + 3));
+ *p = 0;
+ *(p + 1) = 0;
+ *(p + 2) = 0;
+ *(p + 3) = 1;
+ p += (nalsize + 4);
+ }
+ return PLAYER_SUCCESS;
+ } else if (check_size_in_buffer3(p, size)) {
+ while ((p + 3) < (data + size)) {
+ nalsize = (*p << 16) | (*(p + 1) << 8) | (*(p + 2));
+ *p = 0;
+ *(p + 1) = 0;
+ *(p + 2) = 1;
+ p += (nalsize + 3);
+ }
+ return PLAYER_SUCCESS;
+ } else if (check_size_in_buffer2(p, size)) {
+ unsigned char *new_data;
+ int new_len = 0;
+
+ new_data = (unsigned char *)malloc(size + 2 * 1024);
+ if (!new_data) {
+ return PLAYER_NOMEM;
+ }
+
+ while ((p + 2) < (data + size)) {
+ nalsize = (*p << 8) | (*(p + 1));
+ *(new_data + new_len) = 0;
+ *(new_data + new_len + 1) = 0;
+ *(new_data + new_len + 2) = 0;
+ *(new_data + new_len + 3) = 1;
+ memcpy(new_data + new_len + 4, p + 2, nalsize);
+ p += (nalsize + 2);
+ new_len += nalsize + 4;
+ }
+
+ free(pkt->buf);
+
+ pkt->buf = new_data;
+ pkt->buf_size = size + 2 * 1024;
+ pkt->data = pkt->buf;
+ pkt->data_size = new_len;
+ }
+ } else {
+ CLog::Log(LOGDEBUG, "[%s]invalid pointer!", __FUNCTION__);
+ return PLAYER_FAILED;
+ }
+ return PLAYER_SUCCESS;
+}
+
+int divx3_prefix(am_packet_t *pkt)
+{
+#define DIVX311_CHUNK_HEAD_SIZE 13
+ const unsigned char divx311_chunk_prefix[DIVX311_CHUNK_HEAD_SIZE] = {
+ 0x00, 0x00, 0x00, 0x01, 0xb6, 'D', 'I', 'V', 'X', '3', '.', '1', '1'
+ };
+ if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ }
+
+ if (pkt->hdr == NULL) {
+ pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+ if (!pkt->hdr) {
+ CLog::Log(LOGDEBUG, "[divx3_prefix] NOMEM!");
+ return PLAYER_FAILED;
+ }
+
+ pkt->hdr->data = NULL;
+ pkt->hdr->size = 0;
+ }
+
+ pkt->hdr->data = (char*)malloc(DIVX311_CHUNK_HEAD_SIZE + 4);
+ if (pkt->hdr->data == NULL) {
+ CLog::Log(LOGDEBUG, "[divx3_prefix] NOMEM!");
+ return PLAYER_FAILED;
+ }
+
+ memcpy(pkt->hdr->data, divx311_chunk_prefix, DIVX311_CHUNK_HEAD_SIZE);
+
+ pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 0] = (pkt->data_size >> 24) & 0xff;
+ pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 1] = (pkt->data_size >> 16) & 0xff;
+ pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 2] = (pkt->data_size >> 8) & 0xff;
+ pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 3] = pkt->data_size & 0xff;
+
+ pkt->hdr->size = DIVX311_CHUNK_HEAD_SIZE + 4;
+ pkt->newflag = 1;
+
+ return PLAYER_SUCCESS;
+}
+
+int set_header_info(am_private_t *para)
+{
+ am_packet_t *pkt = ¶->am_pkt;
+
+ //if (pkt->newflag)
+ {
+ //if (pkt->hdr)
+ // pkt->hdr->size = 0;
+
+ if ((para->video_format == VFORMAT_H264) /*|| (am_private->video_format == VFORMAT_H264MVC)*/)
+ {
+ return h264_update_frame_header(pkt);
+ }
+ else if (para->video_format == VFORMAT_MPEG4)
+ {
+ if (para->video_codec_type == VIDEO_DEC_FORMAT_MPEG4_3)
+ {
+ return divx3_prefix(pkt);
+ }
+ else if (para->video_codec_type == VIDEO_DEC_FORMAT_H263)
+ {
+ return PLAYER_UNSUPPORT;
+ unsigned char *vld_buf;
+ int vld_len, vld_buf_size = para->video_width * para->video_height * 2;
+
+ if (!pkt->data_size) {
+ return PLAYER_SUCCESS;
+ }
+
+ if ((pkt->data[0] == 0) && (pkt->data[1] == 0) && (pkt->data[2] == 1) && (pkt->data[3] == 0xb6)) {
+ return PLAYER_SUCCESS;
+ }
+
+ vld_buf = (unsigned char*)malloc(vld_buf_size);
+ if (!vld_buf) {
+ return PLAYER_NOMEM;
+ }
+
+ if (para->flv_flag) {
+ vld_len = para->m_dll->h263vld(pkt->data, vld_buf, pkt->data_size, 1);
+ } else {
+ if (0 == para->h263_decodable) {
+ para->h263_decodable = para->m_dll->decodeble_h263(pkt->data);
+ if (0 == para->h263_decodable) {
+ CLog::Log(LOGDEBUG, "[%s]h263 unsupport video and audio, exit", __FUNCTION__);
+ return PLAYER_UNSUPPORT;
+ }
+ }
+ vld_len = para->m_dll->h263vld(pkt->data, vld_buf, pkt->data_size, 0);
+ }
+
+ if (vld_len > 0) {
+ if (pkt->buf) {
+ free(pkt->buf);
+ }
+ pkt->buf = vld_buf;
+ pkt->buf_size = vld_buf_size;
+ pkt->data = pkt->buf;
+ pkt->data_size = vld_len;
+ } else {
+ free(vld_buf);
+ pkt->data_size = 0;
+ }
+ }
+ } else if (para->video_format == VFORMAT_VC1) {
+ if (para->video_codec_type == VIDEO_DEC_FORMAT_WMV3) {
+ unsigned i, check_sum = 0, data_len = 0;
+
+ if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ }
+
+ if (pkt->hdr == NULL) {
+ pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+ if (!pkt->hdr) {
+ return PLAYER_FAILED;
+ }
+
+ pkt->hdr->data = NULL;
+ pkt->hdr->size = 0;
+ }
+
+ if (pkt->avpkt.flags) {
+ pkt->hdr->data = (char*)malloc(para->extrasize + 26 + 22);
+ if (pkt->hdr->data == NULL) {
+ return PLAYER_FAILED;
+ }
+
+ pkt->hdr->data[0] = 0;
+ pkt->hdr->data[1] = 0;
+ pkt->hdr->data[2] = 1;
+ pkt->hdr->data[3] = 0x10;
+
+ data_len = para->extrasize + 4;
+ pkt->hdr->data[4] = 0;
+ pkt->hdr->data[5] = (data_len >> 16) & 0xff;
+ pkt->hdr->data[6] = 0x88;
+ pkt->hdr->data[7] = (data_len >> 8) & 0xff;
+ pkt->hdr->data[8] = data_len & 0xff;
+ pkt->hdr->data[9] = 0x88;
+
+ pkt->hdr->data[10] = 0xff;
+ pkt->hdr->data[11] = 0xff;
+ pkt->hdr->data[12] = 0x88;
+ pkt->hdr->data[13] = 0xff;
+ pkt->hdr->data[14] = 0xff;
+ pkt->hdr->data[15] = 0x88;
+
+ for (i = 4 ; i < 16 ; i++) {
+ check_sum += pkt->hdr->data[i];
+ }
+
+ pkt->hdr->data[16] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[17] = check_sum & 0xff;
+ pkt->hdr->data[18] = 0x88;
+ pkt->hdr->data[19] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[20] = check_sum & 0xff;
+ pkt->hdr->data[21] = 0x88;
+
+ pkt->hdr->data[22] = (para->video_width >> 8) & 0xff;
+ pkt->hdr->data[23] = para->video_width & 0xff;
+ pkt->hdr->data[24] = (para->video_height >> 8) & 0xff;
+ pkt->hdr->data[25] = para->video_height & 0xff;
+
+ memcpy(pkt->hdr->data + 26, para->extradata, para->extrasize);
+
+ check_sum = 0;
+ data_len = para->extrasize + 26;
+ } else {
+ pkt->hdr->data = (char*)malloc(22);
+ if (pkt->hdr->data == NULL) {
+ return PLAYER_FAILED;
+ }
+ }
+
+ pkt->hdr->data[data_len + 0] = 0;
+ pkt->hdr->data[data_len + 1] = 0;
+ pkt->hdr->data[data_len + 2] = 1;
+ pkt->hdr->data[data_len + 3] = 0xd;
+
+ pkt->hdr->data[data_len + 4] = 0;
+ pkt->hdr->data[data_len + 5] = (pkt->data_size >> 16) & 0xff;
+ pkt->hdr->data[data_len + 6] = 0x88;
+ pkt->hdr->data[data_len + 7] = (pkt->data_size >> 8) & 0xff;
+ pkt->hdr->data[data_len + 8] = pkt->data_size & 0xff;
+ pkt->hdr->data[data_len + 9] = 0x88;
+
+ pkt->hdr->data[data_len + 10] = 0xff;
+ pkt->hdr->data[data_len + 11] = 0xff;
+ pkt->hdr->data[data_len + 12] = 0x88;
+ pkt->hdr->data[data_len + 13] = 0xff;
+ pkt->hdr->data[data_len + 14] = 0xff;
+ pkt->hdr->data[data_len + 15] = 0x88;
+
+ for (i = data_len + 4 ; i < data_len + 16 ; i++) {
+ check_sum += pkt->hdr->data[i];
+ }
+
+ pkt->hdr->data[data_len + 16] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[data_len + 17] = check_sum & 0xff;
+ pkt->hdr->data[data_len + 18] = 0x88;
+ pkt->hdr->data[data_len + 19] = (check_sum >> 8) & 0xff;
+ pkt->hdr->data[data_len + 20] = check_sum & 0xff;
+ pkt->hdr->data[data_len + 21] = 0x88;
+
+ pkt->hdr->size = data_len + 22;
+ pkt->newflag = 1;
+ } else if (para->video_codec_type == VIDEO_DEC_FORMAT_WVC1) {
+ if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+ free(pkt->hdr->data);
+ pkt->hdr->data = NULL;
+ }
+
+ if (pkt->hdr == NULL) {
+ pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+ if (!pkt->hdr) {
+ CLog::Log(LOGDEBUG, "[wvc1_prefix] NOMEM!");
+ return PLAYER_FAILED;
+ }
+
+ pkt->hdr->data = NULL;
+ pkt->hdr->size = 0;
+ }
+
+ pkt->hdr->data = (char*)malloc(4);
+ if (pkt->hdr->data == NULL) {
+ CLog::Log(LOGDEBUG, "[wvc1_prefix] NOMEM!");
+ return PLAYER_FAILED;
+ }
+
+ pkt->hdr->data[0] = 0;
+ pkt->hdr->data[1] = 0;
+ pkt->hdr->data[2] = 1;
+ pkt->hdr->data[3] = 0xd;
+ pkt->hdr->size = 4;
+ pkt->newflag = 1;
+ }
+ }
+ }
+ return PLAYER_SUCCESS;
+}
+
+/*************************************************************************/
+CAMLCodec::CAMLCodec() : CThread("CAMLCodec")
+{
+ m_opened = false;
+ am_private = new am_private_t;
+ memset(am_private, 0, sizeof(am_private_t));
+ m_dll = new DllLibAmCodec;
+ m_dll->Load();
+ am_private->m_dll = m_dll;
+}
+
+
+CAMLCodec::~CAMLCodec()
+{
+ StopThread();
+ delete am_private;
+ am_private = NULL;
+ delete m_dll, m_dll = NULL;
+}
+
+bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
+{
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder");
+ m_speed = DVD_PLAYSPEED_NORMAL;
+ m_1st_pts = 0;
+ m_cur_pts = 0;
+ m_cur_pictcnt = 0;
+ m_old_pictcnt = 0;
+ m_dst_rect.SetRect(0, 0, 0, 0);
+ m_zoom = -1;
+ m_contrast = -1;
+ m_brightness = -1;
+ m_vbufsize = 500000 * 2;
+
+ ShowMainVideo(false);
+
+ am_packet_init(&am_private->am_pkt);
+ // default stream type
+ am_private->stream_type = AM_STREAM_ES;
+ // handle hints.
+ am_private->video_width = hints.width;
+ am_private->video_height = hints.height;
+ am_private->video_codec_id = hints.codec;
+ am_private->video_codec_tag = hints.codec_tag;
+ am_private->video_pid = hints.pid;
+
+ // handle video ratio
+ AVRational video_ratio = m_dll->av_d2q(1, SHRT_MAX);
+ //if (!hints.forced_aspect)
+ // video_ratio = m_dll->av_d2q(hints.aspect, SHRT_MAX);
+ am_private->video_ratio = ((int32_t)video_ratio.num << 16) | video_ratio.den;
+ am_private->video_ratio64 = ((int64_t)video_ratio.num << 32) | video_ratio.den;
+
+ // handle video rate
+ if (hints.rfpsrate > 0 && hints.rfpsscale != 0)
+ {
+ // check ffmpeg r_frame_rate 1st
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * hints.rfpsscale / hints.rfpsrate;
+ }
+ else if (hints.fpsrate > 0 && hints.fpsscale != 0)
+ {
+ // then ffmpeg avg_frame_rate next
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * hints.fpsscale / hints.fpsrate;
+ }
+ else
+ {
+ // stupid PVR hacks because it does not fill in all of hints.
+ if (hints.codec == CODEC_ID_MPEG2VIDEO)
+ {
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 30000;
+ if (hints.width == 1280)
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 60000;;
+ }
+ }
+ // check for 1920x1080, interlaced, 25 fps
+ // incorrectly reported as 50 fps (yes, video_rate == 1920)
+ if (hints.width == 1920 && am_private->video_rate == 1920)
+ {
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 25000;
+ }
+
+ // check for SD h264 content incorrectly reported as 60 fsp
+ // mp4/avi containers :(
+ if (hints.codec == CODEC_ID_H264 && hints.width <= 720 && am_private->video_rate == 1602)
+ {
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 24000;
+ }
+
+ // check for SD h264 content incorrectly reported as some form of 30 fsp
+ // mp4/avi containers :(
+ if (hints.codec == CODEC_ID_H264 && hints.width <= 720)
+ {
+ if (am_private->video_rate >= 3200 && am_private->video_rate <= 3210)
+ {
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+ am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 24000;
+ }
+ }
+
+ // handle orientation
+ am_private->video_rotation_degree = 0;
+ if (hints.orientation == 90)
+ am_private->video_rotation_degree = 1;
+ else if (hints.orientation == 180)
+ am_private->video_rotation_degree = 2;
+ else if (hints.orientation == 270)
+ am_private->video_rotation_degree = 3;
+ // handle extradata
+ am_private->video_format = codecid_to_vformat(hints.codec);
+ switch (am_private->video_format)
+ {
+ default:
+ am_private->extrasize = hints.extrasize;
+ am_private->extradata = (uint8_t*)malloc(hints.extrasize);
+ memcpy(am_private->extradata, hints.extradata, hints.extrasize);
+ break;
+ case VFORMAT_REAL:
+ case VFORMAT_MPEG12:
+ break;
+ }
+
+ if (am_private->stream_type == AM_STREAM_ES && am_private->video_codec_tag != 0)
+ am_private->video_codec_type = codec_tag_to_vdec_type(am_private->video_codec_tag);
+ else
+ am_private->video_codec_type = codec_tag_to_vdec_type(am_private->video_codec_id);
+
+ am_private->flv_flag = 0;
+ if (am_private->video_codec_id == CODEC_ID_FLV1)
+ {
+ am_private->video_codec_tag = CODEC_TAG_F263;
+ am_private->flv_flag = 1;
+ }
+
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.fpsrate(%d), hints.fpsscale(%d), hints.rfpsrate(%d), hints.rfpsscale(%d), video_rate(%d)",
+ hints.fpsrate, hints.fpsscale, hints.rfpsrate, hints.rfpsscale, am_private->video_rate);
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.aspect(%f), video_ratio.num(%d), video_ratio.den(%d)",
+ hints.aspect, video_ratio.num, video_ratio.den);
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.orientation(%d), hints.forced_aspect(%d)",
+ hints.orientation, hints.forced_aspect);
+
+ // default video codec params
+ am_private->vcodec.has_video = 1;
+ am_private->vcodec.noblock = 0;
+ am_private->vcodec.video_pid = am_private->video_pid;
+ am_private->vcodec.video_type = am_private->video_format;
+ am_private->vcodec.stream_type = STREAM_TYPE_ES_VIDEO;
+ am_private->vcodec.am_sysinfo.format = am_private->video_codec_type;
+ am_private->vcodec.am_sysinfo.width = am_private->video_width;
+ am_private->vcodec.am_sysinfo.height = am_private->video_height;
+ am_private->vcodec.am_sysinfo.rate = am_private->video_rate;
+ am_private->vcodec.am_sysinfo.ratio = am_private->video_ratio;
+ am_private->vcodec.am_sysinfo.ratio64 = am_private->video_ratio64;
+ am_private->vcodec.am_sysinfo.param = NULL;
+
+ switch(am_private->video_format)
+ {
+ default:
+ break;
+ case VFORMAT_MPEG4:
+ am_private->vcodec.am_sysinfo.param = (void*)EXTERNAL_PTS;
+ break;
+ case VFORMAT_H264:
+ case VFORMAT_H264MVC:
+ am_private->vcodec.am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
+ am_private->vcodec.am_sysinfo.param = (void*)EXTERNAL_PTS;
+ // h264 in an avi file
+ if (hints.ptsinvalid)
+ am_private->vcodec.am_sysinfo.param = (void*)(EXTERNAL_PTS | SYNC_OUTSIDE);
+ break;
+ case VFORMAT_REAL:
+ am_private->stream_type = AM_STREAM_RM;
+ am_private->vcodec.stream_type = STREAM_TYPE_RM;
+ am_private->vcodec.am_sysinfo.ratio = 0x100;
+ am_private->vcodec.am_sysinfo.ratio64 = 0;
+ {
+ static unsigned short tbl[9] = {0};
+ if (VIDEO_DEC_FORMAT_REAL_8 == am_private->video_codec_type)
+ {
+ am_private->vcodec.am_sysinfo.extra = am_private->extradata[1] & 7;
+ tbl[0] = (((am_private->vcodec.am_sysinfo.width >> 2) - 1) << 8)
+ | (((am_private->vcodec.am_sysinfo.height >> 2) - 1) & 0xff);
+ unsigned int j;
+ for (unsigned int i = 1; i <= am_private->vcodec.am_sysinfo.extra; i++)
+ {
+ j = 2 * (i - 1);
+ tbl[i] = ((am_private->extradata[8 + j] - 1) << 8) | ((am_private->extradata[8 + j + 1] - 1) & 0xff);
+ }
+ }
+ am_private->vcodec.am_sysinfo.param = &tbl;
+ }
+ break;
+ case VFORMAT_VC1:
+ // vc1 in an avi file
+ if (hints.ptsinvalid)
+ am_private->vcodec.am_sysinfo.param = (void*)EXTERNAL_PTS;
+ break;
+ }
+ am_private->vcodec.am_sysinfo.param = (void *)((unsigned int)am_private->vcodec.am_sysinfo.param | (am_private->video_rotation_degree << 16));
+
+ int ret = m_dll->codec_init(&am_private->vcodec);
+ if (ret != CODEC_ERROR_NONE)
+ {
+ CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder codec init failed, ret=0x%x", -ret);
+ return false;
+ }
+ // make sure we are not stuck in pause (amcodec bug)
+ m_dll->codec_resume(&am_private->vcodec);
+ m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+
+ m_dll->codec_set_cntl_avthresh(&am_private->vcodec, AV_SYNC_THRESH);
+ m_dll->codec_set_cntl_syncthresh(&am_private->vcodec, 0);
+ // disable tsync, we are playing video disconnected from audio.
+ aml_set_sysfs_int("/sys/class/tsync/enable", 0);
+
+ am_private->am_pkt.codec = &am_private->vcodec;
+ pre_header_feeding(am_private, &am_private->am_pkt);
+
+ Create();
+
+ g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
+ g_renderManager.RegisterRenderFeaturesCallBack((const void*)this, RenderFeaturesCallBack);
+
+ m_opened = true;
+
+ return true;
+}
+
+void CAMLCodec::CloseDecoder()
+{
+ CLog::Log(LOGDEBUG, "CAMLCodec::CloseDecoder");
+ StopThread();
+
+ g_renderManager.RegisterRenderUpdateCallBack((const void*)NULL, NULL);
+ g_renderManager.RegisterRenderFeaturesCallBack((const void*)NULL, NULL);
+
+ m_dll->codec_close(&am_private->vcodec);
+ m_opened = false;
+
+ am_packet_release(&am_private->am_pkt);
+ free(am_private->extradata);
+ am_private->extradata = NULL;
+ // return tsync to default so external apps work
+ aml_set_sysfs_int("/sys/class/tsync/enable", 1);
+
+ ShowMainVideo(false);
+
+}
+
+void CAMLCodec::Reset()
+{
+ CLog::Log(LOGDEBUG, "CAMLCodec::Reset");
+
+ if (!m_opened)
+ return;
+
+ // set the system blackout_policy to leave the last frame showing
+ int blackout_policy = aml_get_sysfs_int("/sys/class/video/blackout_policy");
+ aml_set_sysfs_int("/sys/class/video/blackout_policy", 0);
+
+ // restore the speed (some amcodec versions require this)
+ if (m_speed != DVD_PLAYSPEED_NORMAL)
+ {
+ m_dll->codec_resume(&am_private->vcodec);
+ m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+ }
+ // reset the decoder
+ m_dll->codec_reset(&am_private->vcodec);
+
+ // re-init our am_pkt
+ am_packet_release(&am_private->am_pkt);
+ am_packet_init(&am_private->am_pkt);
+ am_private->am_pkt.codec = &am_private->vcodec;
+ pre_header_feeding(am_private, &am_private->am_pkt);
+
+ // reset some interal vars
+ m_speed = DVD_PLAYSPEED_NORMAL;
+ m_1st_pts = 0;
+ m_cur_pts = 0;
+ m_cur_pictcnt = 0;
+ m_old_pictcnt = 0;
+
+ // restore the saved system blackout_policy value
+ aml_set_sysfs_int("/sys/class/video/blackout_policy", blackout_policy);
+}
+
+int CAMLCodec::Decode(unsigned char *pData, size_t size, double dts, double pts)
+{
+ if (!m_opened)
+ return VC_BUFFER;
+
+ // grr, m_RenderUpdateCallBackFn in g_renderManager is NULL'ed during
+ // g_renderManager.Configure call by player, which happens after the codec
+ // OpenDecoder call. So we need to restore it but it does not seem to stick :)
+ g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
+
+ if (pData)
+ {
+ am_private->am_pkt.data = pData;
+ am_private->am_pkt.data_size = size;
+ am_private->am_pkt.newflag = 1;
+ am_private->am_pkt.isvalid = 1;
+ am_private->am_pkt.avduration = 0;
+
+ if (pts == DVD_NOPTS_VALUE)
+ am_private->am_pkt.avpts = AV_NOPTS_VALUE;
+ else
+ am_private->am_pkt.avpts = 0.5 + (pts * PTS_FREQ) / DVD_TIME_BASE;
+
+ if (dts == DVD_NOPTS_VALUE)
+ am_private->am_pkt.avdts = AV_NOPTS_VALUE;
+ else
+ am_private->am_pkt.avdts = 0.5 + (dts * PTS_FREQ) / DVD_TIME_BASE;
+
+ //CLog::Log(LOGDEBUG, "CAMLCodec::Decode: dts(%f), pts(%f), avdts(%llx), avpts(%llx)",
+ // dts, pts, am_private->am_pkt.avdts, am_private->am_pkt.avpts);
+
+ set_header_info(am_private);
+ write_av_packet(am_private, &am_private->am_pkt);
+
+ // if we seek, then GetTimeSize is wrong as
+ // reports lastpts - cur_pts and hw decoder has
+ // not started outputing new pts values yet.
+ // so we grab the 1st pts sent into driver and
+ // use that to calc GetTimeSize.
+ if (m_1st_pts == 0)
+ m_1st_pts = am_private->am_pkt.lastpts;
+ }
+
+ // if we have still frames, demux size will be small
+ // and we need to pre-buffer more.
+ double target_timesize = 1.0;
+ if (size < 20)
+ target_timesize = 2.0;
+
+ // keep hw buffered demux above 1 second
+ if (GetTimeSize() < target_timesize && m_speed == DVD_PLAYSPEED_NORMAL)
+ {
+ return VC_BUFFER;
+ }
+
+ // wait until we get a new frame or 100ms,
+ if (m_old_pictcnt == m_cur_pictcnt)
+ m_ready_event.WaitMSec(100);
+
+ // we must return VC_BUFFER or VC_PICTURE,
+ // default to VC_BUFFER.
+ int rtn = VC_BUFFER;
+ if (m_old_pictcnt != m_cur_pictcnt)
+ {
+ m_old_pictcnt = m_cur_pictcnt;
+ rtn = VC_PICTURE;
+ // we got a new pict, try and keep hw buffered demux above 2 seconds.
+ // this, combined with the above 1 second check, keeps hw buffered demux between 1 and 2 seconds.
+ // we also check to make sure we keep from filling hw buffer.
+ if (GetTimeSize() < 2.0 && GetDataSize() < m_vbufsize/3)
+ rtn |= VC_BUFFER;
+ }
+/*
+ CLog::Log(LOGDEBUG, "CAMLCodec::Decode: "
+ "rtn(%d), m_cur_pictcnt(%lld), m_cur_pts(%f), lastpts(%f), GetTimeSize(%f), GetDataSize(%d)",
+ rtn, m_cur_pictcnt, (float)m_cur_pts/PTS_FREQ, (float)am_private->am_pkt.lastpts/PTS_FREQ, GetTimeSize(), GetDataSize());
+*/
+ return rtn;
+}
+
+bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture)
+{
+ if (!m_opened)
+ return false;
+
+ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
+ pDvdVideoPicture->format = RENDER_FMT_BYPASS;
+ pDvdVideoPicture->iDuration = (double)(am_private->video_rate * DVD_TIME_BASE) / UNIT_FREQ;
+
+ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
+ pDvdVideoPicture->pts = GetPlayerPtsSeconds() * (double)DVD_TIME_BASE;
+ // video pts cannot be late or dvdplayer goes nuts,
+ // so run it one frame ahead
+ pDvdVideoPicture->pts += 1 * pDvdVideoPicture->iDuration;
+
+ return true;
+}
+
+void CAMLCodec::SetSpeed(int speed)
+{
+ CLog::Log(LOGDEBUG, "CAMLCodec::SetSpeed, speed(%d)", speed);
+
+ if (!m_opened)
+ return;
+
+ if (m_speed != speed)
+ {
+ switch(speed)
+ {
+ case DVD_PLAYSPEED_PAUSE:
+ m_dll->codec_pause(&am_private->vcodec);
+ m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+ break;
+ case DVD_PLAYSPEED_NORMAL:
+ m_dll->codec_resume(&am_private->vcodec);
+ m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+ break;
+ default:
+ Reset();
+ m_dll->codec_resume(&am_private->vcodec);
+ m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_I);
+ //m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_FFFB);
+ break;
+ }
+ m_speed = speed;
+ }
+}
+
+int CAMLCodec::GetDataSize()
+{
+ if (!m_opened)
+ return 0;
+
+ struct buf_status vbuf ={0};
+ if (m_dll->codec_get_vbuf_state(&am_private->vcodec, &vbuf) >= 0)
+ m_vbufsize = vbuf.size;
+
+ return vbuf.data_len;
+}
+
+double CAMLCodec::GetTimeSize()
+{
+ if (!m_opened)
+ return 0;
+
+ // if m_cur_pts is zero, hw decoder was not started yet
+ // so we use the pts of the 1st demux packet that was send
+ // to hw decoder to calc timesize.
+ if (m_cur_pts == 0)
+ m_timesize = (double)(am_private->am_pkt.lastpts - m_1st_pts) / PTS_FREQ;
+ else
+ m_timesize = (double)(am_private->am_pkt.lastpts - m_cur_pts) / PTS_FREQ;
+
+ // lie to DVDPlayer, it is hardcoded to a max of 8 seconds,
+ // if you buffer more than 8 seconds, it goes nuts.
+ double timesize = m_timesize;
+ if (timesize < 0.0)
+ timesize = 0.0;
+ else if (timesize > 7.0)
+ timesize = 7.0;
+
+ return timesize;
+}
+
+void CAMLCodec::Process()
+{
+ CLog::Log(LOGDEBUG, "CAMLCodec::Process Started");
+
+ // bump our priority to be level with SoftAE
+ SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
+ while (!m_bStop)
+ {
+ int64_t pts_video = 0;
+ if (am_private->am_pkt.lastpts > 0)
+ {
+ // this is a blocking poll that returns every vsync.
+ // since we are running at a higher priority, make sure
+ // we sleep if the call fails or does a timeout.
+ if (m_dll->codec_poll_cntl(&am_private->vcodec) < 0)
+ {
+ CLog::Log(LOGDEBUG, "CAMLCodec::Process: codec_poll_cntl failed");
+ Sleep(10);
+ }
+
+ pts_video = get_pts_video();
+ if (m_cur_pts != pts_video)
+ {
+ //CLog::Log(LOGDEBUG, "CAMLCodec::Process: pts_video(%lld), pts_video/PTS_FREQ(%f), duration(%f)",
+ // pts_video, (double)pts_video/PTS_FREQ, 1.0/((double)(pts_video - m_cur_pts)/PTS_FREQ));
+ // other threads look at these, do them first
+ m_cur_pts = pts_video;
+ m_cur_pictcnt++;
+ m_ready_event.Set();
+
+ double app_pts = GetPlayerPtsSeconds();
+ // add in audio delay/display latency contribution
+ double offset = g_renderManager.GetDisplayLatency() - g_settings.m_currentVideoSettings.m_AudioDelay;
+ // correct video pts by user set delay and rendering delay
+ app_pts += offset;
+
+ double error = app_pts - (double)pts_video/PTS_FREQ;
+ double abs_error = fabs(error);
+ if (abs_error > 0.040)
+ {
+ //CLog::Log(LOGDEBUG, "CAMLCodec::Process pts diff = %f", error);
+ if (abs_error > 0.125)
+ {
+ // big error so try to reset pts_pcrscr
+ SetVideoPtsSeconds(app_pts);
+ }
+ else
+ {
+ // small error so try to avoid a frame jump
+ SetVideoPtsSeconds((double)pts_video/PTS_FREQ + error/4);
+ }
+ }
+ }
+ }
+ else
+ {
+ Sleep(10);
+ }
+ }
+ SetPriority(THREAD_PRIORITY_NORMAL);
+ CLog::Log(LOGDEBUG, "CAMLCodec::Process Stopped");
+}
+
+double CAMLCodec::GetPlayerPtsSeconds()
+{
+ double clock_pts = 0.0;
+ CDVDClock *playerclock = CDVDClock::GetMasterClock();
+ if (playerclock)
+ clock_pts = playerclock->GetClock() / DVD_TIME_BASE;
+
+ return clock_pts;
+}
+
+void CAMLCodec::SetVideoPtsSeconds(const double pts)
+{
+ //CLog::Log(LOGDEBUG, "CAMLCodec::SetVideoPtsSeconds: pts(%f)", pts);
+ if (pts >= 0.0)
+ set_pts_pcrscr((int64_t)(pts * PTS_FREQ));
+}
+
+void CAMLCodec::ShowMainVideo(const bool show)
+{
+ static int saved_disable_video = -1;
+
+ int disable_video = show ? 0:1;
+ if (saved_disable_video == disable_video)
+ return;
+
+ aml_set_sysfs_int("/sys/class/video/disable_video", disable_video);
+ saved_disable_video = disable_video;
+}
+
+void CAMLCodec::SetVideoZoom(const float zoom)
+{
+ // input zoom range is 0.5 to 2.0 with a default of 1.0.
+ // output zoom range is 2 to 300 with default of 100.
+ // we limit that to a range of 50 to 200 with default of 100.
+ aml_set_sysfs_int("/sys/class/video/zoom", (int)(100 * zoom));
+}
+
+void CAMLCodec::SetVideoContrast(const int contrast)
+{
+ // input contrast range is 0 to 100 with default of 50.
+ // output contrast range is -255 to 255 with default of 0.
+ int aml_contrast = (255 * (contrast - 50)) / 50;
+ aml_set_sysfs_int("/sys/class/video/contrast", aml_contrast);
+}
+void CAMLCodec::SetVideoBrightness(const int brightness)
+{
+ // input brightness range is 0 to 100 with default of 50.
+ // output brightness range is -127 to 127 with default of 0.
+ int aml_brightness = (127 * (brightness - 50)) / 50;
+ aml_set_sysfs_int("/sys/class/video/brightness", aml_brightness);
+}
+void CAMLCodec::SetVideoSaturation(const int saturation)
+{
+ // output saturation range is -127 to 127 with default of 127.
+ aml_set_sysfs_int("/sys/class/video/saturation", saturation);
+}
+
+void CAMLCodec::GetRenderFeatures(Features &renderFeatures)
+{
+ renderFeatures.push_back(RENDERFEATURE_ZOOM);
+ renderFeatures.push_back(RENDERFEATURE_CONTRAST);
+ renderFeatures.push_back(RENDERFEATURE_BRIGHTNESS);
+ renderFeatures.push_back(RENDERFEATURE_STRETCH);
+ renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
+ return;
+}
+
+void CAMLCodec::RenderFeaturesCallBack(const void *ctx, Features &renderFeatures)
+{
+ CAMLCodec *codec = (CAMLCodec*)ctx;
+ if (codec)
+ codec->GetRenderFeatures(renderFeatures);
+}
+
+void CAMLCodec::SetVideoRect(const CRect &SrcRect, const CRect &DestRect)
+{
+ // this routine gets called every video frame
+ // and is in the context of the renderer thread so
+ // do not do anything stupid here.
+
+ // video zoom adjustment.
+ float zoom = g_settings.m_currentVideoSettings.m_CustomZoomAmount;
+ if ((int)(zoom * 1000) != (int)(m_zoom * 1000))
+ {
+ m_zoom = zoom;
+ }
+ // video contrast adjustment.
+ int contrast = g_settings.m_currentVideoSettings.m_Contrast;
+ if (contrast != m_contrast)
+ {
+ SetVideoContrast(contrast);
+ m_contrast = contrast;
+ }
+ // video brightness adjustment.
+ int brightness = g_settings.m_currentVideoSettings.m_Brightness;
+ if (brightness != m_brightness)
+ {
+ SetVideoBrightness(brightness);
+ m_brightness = brightness;
+ }
+
+ // check if destination rect or video view mode has changed
+ if ((m_dst_rect != DestRect) || (m_view_mode != g_settings.m_currentVideoSettings.m_ViewMode))
+ {
+ m_dst_rect = DestRect;
+ m_view_mode = g_settings.m_currentVideoSettings.m_ViewMode;
+ }
+ else
+ {
+ // mainvideo 'should' be showing already if we get here, make sure.
+ ShowMainVideo(true);
+ return;
+ }
+
+ CRect gui, display, dst_rect;
+ gui = g_graphicsContext.GetViewWindow();
+ // when display is at 1080p, we have freescale enabled
+ // and that scales all layers into 1080p display including video,
+ // so we have to setup video axis for 720p instead of 1080p... Boooo.
+ display = g_graphicsContext.GetViewWindow();
+ //RESOLUTION res = g_graphicsContext.GetVideoResolution();
+ //display.SetRect(0, 0, g_settings.m_ResInfo[res].iScreenWidth, g_settings.m_ResInfo[res].iScreenHeight);
+ dst_rect = m_dst_rect;
+ if (gui != display)
+ {
+ float xscale = display.Width() / gui.Width();
+ float yscale = display.Height() / gui.Height();
+ dst_rect.x1 *= xscale;
+ dst_rect.x2 *= xscale;
+ dst_rect.y1 *= yscale;
+ dst_rect.y2 *= yscale;
+ }
+
+ ShowMainVideo(false);
+
+ // goofy 0/1 based difference in aml axis coordinates.
+ // fix them.
+ dst_rect.x2--;
+ dst_rect.y2--;
+
+ char video_axis[256] = {0};
+ sprintf(video_axis, "%d %d %d %d", (int)dst_rect.x1, (int)dst_rect.y1, (int)dst_rect.x2, (int)dst_rect.y2);
+ aml_set_sysfs_str("/sys/class/video/axis", video_axis);
+ // make sure we are in 'full stretch' so we can stretch
+ aml_set_sysfs_int("/sys/class/video/screen_mode", 1);
+
+/*
+ CStdString rectangle;
+ rectangle.Format("%i,%i,%i,%i",
+ (int)dst_rect.x1, (int)dst_rect.y1,
+ (int)dst_rect.Width(), (int)dst_rect.Height());
+ CLog::Log(LOGDEBUG, "CAMLCodec::SetVideoRect:dst_rect(%s)", rectangle.c_str());
+*/
+
+ // we only get called once gui has changed to something
+ // that would show video playback, so show it.
+ ShowMainVideo(true);
+}
+
+void CAMLCodec::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
+{
+ CAMLCodec *codec = (CAMLCodec*)ctx;
+ codec->SetVideoRect(SrcRect, DestRect);
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h
new file mode 100644
index 0000000000000..9da94e9ec3ea9
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h
@@ -0,0 +1,83 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "DVDVideoCodec.h"
+#include "cores/dvdplayer/DVDStreamInfo.h"
+#include "cores/VideoRenderers/RenderFeatures.h"
+#include "guilib/Geometry.h"
+#include "threads/Thread.h"
+
+typedef struct am_private_t am_private_t;
+
+class DllLibAmCodec;
+
+class CAMLCodec : public CThread
+{
+public:
+ CAMLCodec();
+ virtual ~CAMLCodec();
+
+ bool OpenDecoder(CDVDStreamInfo &hints);
+ void CloseDecoder();
+ void Reset();
+
+ int Decode(unsigned char *pData, size_t size, double dts, double pts);
+
+ bool GetPicture(DVDVideoPicture* pDvdVideoPicture);
+ void SetSpeed(int speed);
+ int GetDataSize();
+ double GetTimeSize();
+
+protected:
+ virtual void Process();
+
+private:
+ double GetPlayerPtsSeconds();
+ void SetVideoPtsSeconds(double pts);
+ void ShowMainVideo(const bool show);
+ void SetVideoZoom(const float zoom);
+ void SetVideoContrast(const int contrast);
+ void SetVideoBrightness(const int brightness);
+ void SetVideoSaturation(const int saturation);
+ void GetRenderFeatures(Features &renderFeatures);
+ static void RenderFeaturesCallBack(const void *ctx, Features &renderFeatures);
+ void SetVideoRect(const CRect &SrcRect, const CRect &DestRect);
+ static void RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
+
+ DllLibAmCodec *m_dll;
+ bool m_opened;
+ am_private_t *am_private;
+ volatile int m_speed;
+ volatile int64_t m_1st_pts;
+ volatile int64_t m_cur_pts;
+ volatile int64_t m_cur_pictcnt;
+ volatile int64_t m_old_pictcnt;
+ volatile double m_timesize;
+ volatile int64_t m_vbufsize;
+ CEvent m_ready_event;
+
+ CRect m_dst_rect;
+ int m_view_mode;
+ float m_zoom;
+ int m_contrast;
+ int m_brightness;
+};
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
index 1d8bad38525cd..104cbbf58cffe 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -191,6 +191,12 @@ class CDVDVideoCodec
*/
virtual void SetDropState(bool bDrop) = 0;
+ /*
+ * will be called by video player indicating the playback speed. see DVD_PLAYSPEED_NORMAL,
+ * DVD_PLAYSPEED_PAUSE and friends.
+ */
+ virtual void SetSpeed(int iSpeed) {};
+
/*
* returns the number of demuxer bytes in any internal buffers
*/
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp
new file mode 100644
index 0000000000000..2c8fb03e0d0bc
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include
+
+#include "DVDVideoCodecAmlogic.h"
+#include "DVDClock.h"
+#include "DVDStreamInfo.h"
+#include "AMLCodec.h"
+#include "video/VideoThumbLoader.h"
+#include "utils/log.h"
+
+#define __MODULE_NAME__ "DVDVideoCodecAmlogic"
+
+typedef struct pts_queue {
+ double dts;
+ double pts;
+ double sort_time;
+ struct pts_queue *nextpts;
+} pts_queue;
+
+CDVDVideoCodecAmlogic::CDVDVideoCodecAmlogic() :
+ m_Codec(NULL),
+ m_pFormatName("amcodec"),
+ m_last_pts(0.0),
+ m_pts_queue(NULL),
+ m_queue_depth(0),
+ m_framerate(0.0),
+ m_video_rate(0)
+{
+ pthread_mutex_init(&m_queue_mutex, NULL);
+}
+
+CDVDVideoCodecAmlogic::~CDVDVideoCodecAmlogic()
+{
+ Dispose();
+ pthread_mutex_destroy(&m_queue_mutex);
+}
+
+bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+{
+ switch(hints.codec)
+ {
+ case CODEC_ID_MJPEG:
+ m_pFormatName = "am-mjpeg";
+ break;
+ case CODEC_ID_MPEG1VIDEO:
+ case CODEC_ID_MPEG2VIDEO:
+ case CODEC_ID_MPEG2VIDEO_XVMC:
+ m_pFormatName = "am-mpeg2";
+ break;
+ case CODEC_ID_H264:
+ m_pFormatName = "am-h264";
+ break;
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_MSMPEG4V2:
+ case CODEC_ID_MSMPEG4V3:
+ m_pFormatName = "am-mpeg4";
+ break;
+ case CODEC_ID_H263:
+ case CODEC_ID_H263P:
+ case CODEC_ID_H263I:
+ m_pFormatName = "am-h263";
+ break;
+ case CODEC_ID_FLV1:
+ m_pFormatName = "am-flv1";
+ break;
+ case CODEC_ID_RV10:
+ case CODEC_ID_RV20:
+ case CODEC_ID_RV30:
+ case CODEC_ID_RV40:
+ m_pFormatName = "am-rv";
+ break;
+ case CODEC_ID_VC1:
+ m_pFormatName = "am-vc1";
+ break;
+ case CODEC_ID_WMV3:
+ m_pFormatName = "am-wmv3";
+ break;
+ case CODEC_ID_AVS:
+ case CODEC_ID_CAVS:
+ m_pFormatName = "am-avs";
+ break;
+ default:
+ CLog::Log(LOGDEBUG, "%s: Unknown hints.codec(%d", __MODULE_NAME__, hints.codec);
+ return false;
+ break;
+ }
+
+ m_hints = hints;
+ m_Codec = new CAMLCodec();
+ if (!m_Codec)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to create Amlogic Codec", __MODULE_NAME__);
+ return false;
+ }
+ m_opened = false;
+
+ // allocate a dummy DVDVideoPicture buffer.
+ // first make sure all properties are reset.
+ memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
+
+ m_videobuffer.dts = DVD_NOPTS_VALUE;
+ m_videobuffer.pts = DVD_NOPTS_VALUE;
+ m_videobuffer.format = RENDER_FMT_BYPASS;
+ m_videobuffer.color_range = 0;
+ m_videobuffer.color_matrix = 4;
+ m_videobuffer.iFlags = DVP_FLAG_ALLOCATED;
+ m_videobuffer.iWidth = hints.width;
+ m_videobuffer.iHeight = hints.height;
+
+ m_videobuffer.iDisplayWidth = m_videobuffer.iWidth;
+ m_videobuffer.iDisplayHeight = m_videobuffer.iHeight;
+ if (hints.aspect > 0.0 && !hints.forced_aspect)
+ {
+ m_videobuffer.iDisplayWidth = ((int)lrint(m_videobuffer.iHeight * hints.aspect)) & -3;
+ if (m_videobuffer.iDisplayWidth > m_videobuffer.iWidth)
+ {
+ m_videobuffer.iDisplayWidth = m_videobuffer.iWidth;
+ m_videobuffer.iDisplayHeight = ((int)lrint(m_videobuffer.iWidth / hints.aspect)) & -3;
+ }
+ }
+
+ CJobManager::GetInstance().Pause(kJobTypeMediaFlags);
+ if (CJobManager::GetInstance().IsProcessing(kJobTypeMediaFlags) > 0)
+ {
+ int timeout_ms = 5000;
+ while (timeout_ms > 0)
+ {
+ if (CJobManager::GetInstance().IsProcessing(kJobTypeMediaFlags) > 0)
+ {
+ Sleep(100);
+ timeout_ms -= 100;
+ }
+ else
+ break;
+ }
+ }
+
+ CLog::Log(LOGINFO, "%s: Opened Amlogic Codec", __MODULE_NAME__);
+ return true;
+}
+
+void CDVDVideoCodecAmlogic::Dispose(void)
+{
+ if (m_Codec)
+ m_Codec->CloseDecoder(), m_Codec = NULL;
+ if (m_videobuffer.iFlags)
+ m_videobuffer.iFlags = 0;
+ while (m_queue_depth)
+ PtsQueuePop();
+
+ // let thumbgen jobs resume.
+ CJobManager::GetInstance().UnPause(kJobTypeMediaFlags);
+}
+
+int CDVDVideoCodecAmlogic::Decode(BYTE *pData, int iSize, double dts, double pts)
+{
+ // Handle Input, add demuxer packet to input queue, we must accept it or
+ // it will be discarded as DVDPlayerVideo has no concept of "try again".
+
+ if (!m_opened)
+ {
+ if (m_Codec && !m_Codec->OpenDecoder(m_hints))
+ CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__);
+ m_opened = true;
+ }
+
+ if (m_hints.ptsinvalid)
+ pts = DVD_NOPTS_VALUE;
+
+ if (pData)
+ FrameRateTracking(dts, pts);
+
+ return m_Codec->Decode(pData, iSize, dts, pts);
+}
+
+void CDVDVideoCodecAmlogic::Reset(void)
+{
+ while (m_queue_depth)
+ PtsQueuePop();
+
+ m_Codec->Reset();
+}
+
+bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+{
+ if (m_Codec)
+ m_Codec->GetPicture(&m_videobuffer);
+ *pDvdVideoPicture = m_videobuffer;
+
+ return true;
+}
+
+void CDVDVideoCodecAmlogic::SetDropState(bool bDrop)
+{
+}
+
+void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed)
+{
+ if (m_Codec)
+ m_Codec->SetSpeed(iSpeed);
+}
+
+int CDVDVideoCodecAmlogic::GetDataSize(void)
+{
+ if (m_Codec)
+ return m_Codec->GetDataSize();
+ else
+ return 0;
+}
+
+double CDVDVideoCodecAmlogic::GetTimeSize(void)
+{
+ if (m_Codec)
+ return m_Codec->GetTimeSize();
+ else
+ return 0;
+}
+
+void CDVDVideoCodecAmlogic::PtsQueuePop(void)
+{
+ if (!m_pts_queue || m_queue_depth == 0)
+ return;
+
+ pthread_mutex_lock(&m_queue_mutex);
+ // pop the top frame off the queue
+ pts_queue *top_pts = m_pts_queue;
+ m_pts_queue = top_pts->nextpts;
+ m_queue_depth--;
+ pthread_mutex_unlock(&m_queue_mutex);
+
+ // and release it
+ free(top_pts);
+}
+
+void CDVDVideoCodecAmlogic::PtsQueuePush(double dts, double pts)
+{
+ pts_queue *newpts = (pts_queue*)calloc(sizeof(pts_queue), 1);
+ newpts->dts = dts;
+ newpts->pts = pts;
+ // if both dts or pts are good we use those, else use decoder insert time for frame sort
+ if ((newpts->pts != DVD_NOPTS_VALUE) || (newpts->dts != DVD_NOPTS_VALUE))
+ {
+ // if pts is borked (stupid avi's), use dts for frame sort
+ if (newpts->pts == DVD_NOPTS_VALUE)
+ newpts->sort_time = newpts->dts;
+ else
+ newpts->sort_time = newpts->pts;
+ }
+
+ pthread_mutex_lock(&m_queue_mutex);
+ pts_queue *queueWalker = m_pts_queue;
+ if (!queueWalker || (newpts->sort_time < queueWalker->sort_time))
+ {
+ // we have an empty queue, or this frame earlier than the current queue head.
+ newpts->nextpts = queueWalker;
+ m_pts_queue = newpts;
+ } else {
+ // walk the queue and insert this frame where it belongs in display order.
+ bool ptrInserted = false;
+ pts_queue *nextpts = NULL;
+ //
+ while (!ptrInserted)
+ {
+ nextpts = queueWalker->nextpts;
+ if (!nextpts || (newpts->sort_time < nextpts->sort_time))
+ {
+ // if the next frame is the tail of the queue, or our new frame is earlier.
+ newpts->nextpts = nextpts;
+ queueWalker->nextpts = newpts;
+ ptrInserted = true;
+ }
+ queueWalker = nextpts;
+ }
+ }
+ m_queue_depth++;
+ pthread_mutex_unlock(&m_queue_mutex);
+}
+
+void CDVDVideoCodecAmlogic::FrameRateTracking(double dts, double pts)
+{
+ PtsQueuePush(dts, pts);
+
+ // we might have out-of-order pts,
+ // so make sure we wait for at least 16 values in sorted queue.
+ if (m_queue_depth > 16)
+ {
+ pthread_mutex_lock(&m_queue_mutex);
+
+ float cur_pts = m_pts_queue->pts;
+ if (cur_pts == DVD_NOPTS_VALUE)
+ cur_pts = m_pts_queue->dts;
+
+ pthread_mutex_unlock(&m_queue_mutex);
+
+ float duration = cur_pts - m_last_pts;
+ m_last_pts = cur_pts;
+
+ // clamp duration to sensible range,
+ // 66 fsp to 20 fsp
+ if (duration >= 15000.0 && duration <= 50000.0)
+ {
+ double framerate;
+ switch((int)(0.5 + duration))
+ {
+ // 59.940 (16683.333333)
+ case 16000 ... 17000:
+ framerate = 60000.0 / 1001.0;
+ break;
+
+ // 50.000 (20000.000000)
+ case 20000:
+ framerate = 50000.0 / 1000.0;
+ break;
+
+ // 49.950 (20020.000000)
+ case 20020:
+ framerate = 50000.0 / 1001.0;
+ break;
+
+ // 29.970 (33366.666656)
+ case 32000 ... 35000:
+ framerate = 30000.0 / 1001.0;
+ break;
+
+ // 25.000 (40000.000000)
+ case 40000:
+ framerate = 25000.0 / 1000.0;
+ break;
+
+ // 24.975 (40040.000000)
+ case 40040:
+ framerate = 25000.0 / 1001.0;
+ break;
+
+ /*
+ // 24.000 (41666.666666)
+ case 41667:
+ framerate = 24000.0 / 1000.0;
+ break;
+ */
+
+ // 23.976 (41708.33333)
+ case 40200 ... 43200:
+ // 23.976 seems to have the crappiest encodings :)
+ framerate = 24000.0 / 1001.0;
+ break;
+
+ default:
+ framerate = 0.0;
+ CLog::Log(LOGDEBUG, "%s: unknown duration(%f), cur_pts(%f)",
+ __MODULE_NAME__, duration, cur_pts);
+ break;
+ }
+
+ if (framerate > 0.0 && (int)m_framerate != (int)framerate)
+ {
+ m_framerate = framerate;
+ m_video_rate = (int)(0.5 + (96000.0 / framerate));
+ CLog::Log(LOGDEBUG, "%s: detected new framerate(%f), video_rate(%d)",
+ __MODULE_NAME__, m_framerate, m_video_rate);
+ }
+ }
+
+ PtsQueuePop();
+ }
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h
new file mode 100644
index 0000000000000..04c4eac90adbc
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h
@@ -0,0 +1,63 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "DVDVideoCodec.h"
+#include "DVDStreamInfo.h"
+
+class CAMLCodec;
+typedef struct pts_queue pts_queue;
+
+class CDVDVideoCodecAmlogic : public CDVDVideoCodec
+{
+public:
+ CDVDVideoCodecAmlogic();
+ virtual ~CDVDVideoCodecAmlogic();
+
+ // Required overrides
+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
+ virtual void Dispose(void);
+ virtual int Decode(BYTE *pData, int iSize, double dts, double pts);
+ virtual void Reset(void);
+ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
+ virtual void SetSpeed(int iSpeed);
+ virtual void SetDropState(bool bDrop);
+ virtual int GetDataSize(void);
+ virtual double GetTimeSize(void);
+ virtual const char* GetName(void) { return (const char*)m_pFormatName; }
+
+protected:
+ void PtsQueuePop(void);
+ void PtsQueuePush(double dts, double pts);
+ void FrameRateTracking(double dts, double pts);
+
+ CAMLCodec *m_Codec;
+ const char *m_pFormatName;
+ DVDVideoPicture m_videobuffer;
+ bool m_opened;
+ CDVDStreamInfo m_hints;
+ double m_last_pts;
+ pts_queue *m_pts_queue;
+ int32_t m_queue_depth;
+ pthread_mutex_t m_queue_mutex;
+ double m_framerate;
+ int m_video_rate;
+};
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
index 176ceff899b83..157b6b325efe8 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
@@ -23,6 +23,12 @@ SRCS += OpenMaxVideo.cpp
SRCS += DVDVideoCodecOpenMax.cpp
endif
+ifeq (@USE_LIBAMCODEC@,1)
+SRCS += AMLCodec.cpp
+SRCS += DVDVideoCodecAmlogic.cpp
+INCLUDES += -I$(prefix)/include/amlplayer
+endif
+
LIB=Video.a
include @abs_top_srcdir@/Makefile.include
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
index aac0ccec7b2d6..a48a902b25692 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
@@ -154,6 +154,8 @@ class CDemuxStreamVideo : public CDemuxStream
{
iFpsScale = 0;
iFpsRate = 0;
+ irFpsScale = 0;
+ irFpsRate = 0;
iHeight = 0;
iWidth = 0;
fAspect = 0.0;
@@ -168,6 +170,8 @@ class CDemuxStreamVideo : public CDemuxStream
virtual ~CDemuxStreamVideo() {}
int iFpsScale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
int iFpsRate;
+ int irFpsScale;
+ int irFpsRate;
int iHeight; // height of the stream reported by the demuxer
int iWidth; // width of the stream reported by the demuxer
float fAspect; // display aspect of stream
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index 7c0ab03e0052f..7847947295bfd 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -974,8 +974,8 @@ void CDVDDemuxFFmpeg::AddStream(int iId)
else
st->bVFR = false;
- // never trust pts in avi files with h264.
- if (m_bAVI && pStream->codec->codec_id == CODEC_ID_H264)
+ // never trust pts in avi files
+ if (m_bAVI)
st->bPTSInvalid = true;
//average fps is more accurate for mkv files
@@ -995,6 +995,18 @@ void CDVDDemuxFFmpeg::AddStream(int iId)
st->iFpsScale = 0;
}
+ // added for aml hw decoder, mkv frame-rate can be wrong.
+ if (pStream->r_frame_rate.den && pStream->r_frame_rate.num)
+ {
+ st->irFpsRate = pStream->r_frame_rate.num;
+ st->irFpsScale = pStream->r_frame_rate.den;
+ }
+ else
+ {
+ st->irFpsRate = 0;
+ st->irFpsScale = 0;
+ }
+
if (pStream->codec_info_nb_frames > 0
&& pStream->codec_info_nb_frames <= 2
&& m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 0cd2510056a82..191df88afc233 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -2862,7 +2862,9 @@ bool CDVDPlayer::OpenVideoStream(int iStream, int source, bool reset)
hint.aspect = aspect;
hint.forced_aspect = true;
}
+#if !defined(HAS_LIBAMCODEC)
hint.software = true;
+#endif
}
boost::shared_ptr client;
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
index 23899d20c9e90..a25cdc61f2ea0 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
@@ -645,7 +645,12 @@ void CDVDPlayerAudio::HandleSyncError(double duration)
double error = m_dvdAudio.GetPlayingPts() - clock;
int64_t now;
+//#if defined(TARGET_ANDROID)
+#if 1
+ if( fabs(error) > DVD_MSEC_TO_TIME(250) || m_syncclock )
+#else
if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
+#endif
{
m_pClock->Discontinuity(clock+error);
if(m_speed == DVD_PLAYSPEED_NORMAL)
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 3008c25f845b8..346223505b60b 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -465,6 +465,8 @@ void CDVDPlayerVideo::Process()
m_speed = static_cast(pMsg)->m_value;
if(m_speed == DVD_PLAYSPEED_PAUSE)
m_iNrOfPicturesNotToSkip = 0;
+ if (m_pVideoCodec)
+ m_pVideoCodec->SetSpeed(m_speed);
}
else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
{
@@ -1174,8 +1176,11 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
limited = true;
//correct any pattern in the timestamps
- m_pullupCorrection.Add(pts);
- pts += m_pullupCorrection.GetCorrection();
+ if (m_output.color_format != RENDER_FMT_BYPASS)
+ {
+ m_pullupCorrection.Add(pts);
+ pts += m_pullupCorrection.GetCorrection();
+ }
//try to calculate the framerate
CalcFrameRate();
@@ -1189,8 +1194,11 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
pts -= DVD_TIME_BASE * interval;
}
- // Correct pts by user set delay and rendering delay
- pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
+ if (m_output.color_format != RENDER_FMT_BYPASS)
+ {
+ // Correct pts by user set delay and rendering delay
+ pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
+ }
// calculate the time we need to delay this picture before displaying
double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
diff --git a/xbmc/cores/dvdplayer/DVDStreamInfo.cpp b/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
index 36cf79852ff67..6d6c6fa42b4ce 100644
--- a/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
+++ b/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
@@ -50,6 +50,8 @@ void CDVDStreamInfo::Clear()
fpsscale = 0;
fpsrate = 0;
+ rfpsscale= 0;
+ rfpsrate = 0;
height = 0;
width = 0;
aspect = 0.0;
@@ -60,6 +62,7 @@ void CDVDStreamInfo::Clear()
ptsinvalid = false;
forced_aspect = false;
bitsperpixel = 0;
+ pid = 0;
channels = 0;
samplerate = 0;
@@ -90,6 +93,8 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata)
// VIDEO
if( fpsscale != right.fpsscale
|| fpsrate != right.fpsrate
+ || rfpsscale!= right.rfpsscale
+ || rfpsrate != right.rfpsrate
|| height != right.height
|| width != right.width
|| stills != right.stills
@@ -98,6 +103,7 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata)
|| ptsinvalid != right.ptsinvalid
|| forced_aspect != right.forced_aspect
|| bitsperpixel != right.bitsperpixel
+ || pid != right.pid
|| vfr != right.vfr) return false;
// AUDIO
@@ -145,6 +151,8 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata)
// VIDEO
fpsscale = right.fpsscale;
fpsrate = right.fpsrate;
+ rfpsscale= right.rfpsscale;
+ rfpsrate = right.rfpsrate;
height = right.height;
width = right.width;
aspect = right.aspect;
@@ -155,6 +163,7 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata)
forced_aspect = right.forced_aspect;
orientation = right.orientation;
bitsperpixel = right.bitsperpixel;
+ pid = right.pid;
// AUDIO
channels = right.channels;
@@ -198,6 +207,8 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata)
const CDemuxStreamVideo *stream = static_cast(&right);
fpsscale = stream->iFpsScale;
fpsrate = stream->iFpsRate;
+ rfpsscale = stream->irFpsScale;
+ rfpsrate = stream->irFpsRate;
height = stream->iHeight;
width = stream->iWidth;
aspect = stream->fAspect;
@@ -206,6 +217,7 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata)
forced_aspect = stream->bForcedAspect;
orientation = stream->iOrientation;
bitsperpixel = stream->iBitsPerPixel;
+ pid = stream->iPhysicalId;
}
else if( right.type == STREAM_SUBTITLE )
{
diff --git a/xbmc/cores/dvdplayer/DVDStreamInfo.h b/xbmc/cores/dvdplayer/DVDStreamInfo.h
index e4fec0f047f98..47e5f73c460de 100644
--- a/xbmc/cores/dvdplayer/DVDStreamInfo.h
+++ b/xbmc/cores/dvdplayer/DVDStreamInfo.h
@@ -67,6 +67,8 @@ class CDVDStreamInfo
// VIDEO
int fpsscale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
int fpsrate;
+ int rfpsscale;
+ int rfpsrate;
int height; // height of the stream reported by the demuxer
int width; // width of the stream reported by the demuxer
float aspect; // display aspect as reported by demuxer
@@ -78,6 +80,7 @@ class CDVDStreamInfo
bool forced_aspect; // aspect is forced from container
int orientation; // orientation of the video in degress counter clockwise
int bitsperpixel;
+ int pid;
// AUDIO
int channels;
diff --git a/xbmc/cores/dvdplayer/Edl.cpp b/xbmc/cores/dvdplayer/Edl.cpp
index a07164b09243b..3c27256f3bcd5 100644
--- a/xbmc/cores/dvdplayer/Edl.cpp
+++ b/xbmc/cores/dvdplayer/Edl.cpp
@@ -79,7 +79,7 @@ bool CEdl::ReadEditDecisionLists(const CStdString& strMovie, const float fFrameR
* back frame markers. However, this doesn't seem possible for MythTV.
*/
float fFramesPerSecond;
- if (int(fFrameRate * 100) == 5994) // 59.940 fps = NTSC or 60i content
+ if (iHeight != 720 && int(fFrameRate * 100) == 5994) // 59.940 fps = NTSC or 60i content except for 1280x720/60
{
fFramesPerSecond = fFrameRate / 2; // ~29.97f - division used to retain accuracy of original.
CLog::Log(LOGDEBUG, "%s - Assuming NTSC or 60i interlaced content. Adjusted frames per second from %.3f (~59.940 fps) to %.3f",
diff --git a/xbmc/dialogs/GUIDialogFileBrowser.cpp b/xbmc/dialogs/GUIDialogFileBrowser.cpp
index e4149d1f4b18a..8fe1de39ecd1a 100644
--- a/xbmc/dialogs/GUIDialogFileBrowser.cpp
+++ b/xbmc/dialogs/GUIDialogFileBrowser.cpp
@@ -26,7 +26,6 @@
#include "GUIDialogContextMenu.h"
#include "storage/MediaManager.h"
#include "AutoSwitch.h"
-#include "network/Network.h"
#include "GUIPassword.h"
#include "guilib/GUIWindowManager.h"
#include "Application.h"
@@ -572,7 +571,7 @@ bool CGUIDialogFileBrowser::HaveDiscOrConnection( int iDriveType )
else if ( iDriveType == CMediaSource::SOURCE_TYPE_REMOTE )
{
// TODO: Handle not connected to a remote share
- if ( !g_application.getNetwork().IsConnected() )
+ if ( !g_application.getNetworkManager().IsConnected() )
{
CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
return false;
diff --git a/xbmc/epg/EpgContainer.cpp b/xbmc/epg/EpgContainer.cpp
index 23122a463b747..fb9fba0b85120 100644
--- a/xbmc/epg/EpgContainer.cpp
+++ b/xbmc/epg/EpgContainer.cpp
@@ -444,12 +444,13 @@ bool CEpgContainer::InterruptUpdate(void) const
bool bReturn(false);
CSingleLock lock(m_critSection);
bReturn = g_application.m_bStop || m_bStop || m_bPreventUpdates;
+ const bool isVideoPlaying = g_application.m_pPlayer && g_application.m_pPlayer->IsPlaying();
+ const bool isPVRPlaying = g_PVRManager.IsStarted() && g_PVRManager.IsPlaying();
lock.Leave();
return bReturn ||
(g_guiSettings.GetBool("epg.preventupdateswhileplayingtv") &&
- g_PVRManager.IsStarted() &&
- g_PVRManager.IsPlaying());
+ ( isPVRPlaying || isVideoPlaying ));
}
void CEpgContainer::WaitForUpdateFinish(bool bInterrupt /* = true */)
diff --git a/xbmc/filesystem/DirectoryFactory.cpp b/xbmc/filesystem/DirectoryFactory.cpp
index 9fb21698a8dad..1fcf1afd317db 100644
--- a/xbmc/filesystem/DirectoryFactory.cpp
+++ b/xbmc/filesystem/DirectoryFactory.cpp
@@ -21,7 +21,6 @@
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
-#include "network/Network.h"
#include "system.h"
#include "DirectoryFactory.h"
#include "HDDirectory.h"
@@ -167,7 +166,7 @@ IDirectory* CDirectoryFactory::Create(const CStdString& strPath)
if (strProtocol == "filereader")
return CDirectoryFactory::Create(url.GetFileName());
- if( g_application.getNetwork().IsAvailable(true) ) // true to wait for the network (if possible)
+ if( g_application.getNetworkManager().IsAvailable(true) ) // true to wait for the network (if possible)
{
if (strProtocol == "lastfm") return new CLastFMDirectory();
if (strProtocol == "tuxbox") return new CTuxBoxDirectory();
diff --git a/xbmc/filesystem/FileFactory.cpp b/xbmc/filesystem/FileFactory.cpp
index a042d39e7ddce..41493fbb68af7 100644
--- a/xbmc/filesystem/FileFactory.cpp
+++ b/xbmc/filesystem/FileFactory.cpp
@@ -22,7 +22,6 @@
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
-#include "network/Network.h"
#include "system.h"
#include "FileFactory.h"
#include "HDFile.h"
@@ -144,7 +143,7 @@ IFile* CFileFactory::CreateLoader(const CURL& url)
#endif
else if(strProtocol == "udf") return new CUDFFile();
- if( g_application.getNetwork().IsAvailable() )
+ if( g_application.getNetworkManager().IsAvailable() )
{
if (strProtocol == "dav"
|| strProtocol == "davs"
diff --git a/xbmc/filesystem/ISOFile.cpp b/xbmc/filesystem/ISOFile.cpp
index 9baa95d81e01a..52a556cc85c71 100644
--- a/xbmc/filesystem/ISOFile.cpp
+++ b/xbmc/filesystem/ISOFile.cpp
@@ -87,7 +87,7 @@ unsigned int CISOFile::Read(void *lpBuf, int64_t uiBufSize)
if (m_cache.getMaxWriteSize() > 5000)
{
- byte buffer[5000];
+ BYTE buffer[5000];
long lBytesRead = m_isoReader.ReadFile( m_hFile, buffer, sizeof(buffer));
if (lBytesRead > 0)
m_cache.WriteData((char*)buffer, lBytesRead);
@@ -97,7 +97,7 @@ unsigned int CISOFile::Read(void *lpBuf, int64_t uiBufSize)
}
return lTotalBytesRead;
}
- int iResult = m_isoReader.ReadFile( m_hFile, (byte*)pData, (long)uiBufSize);
+ int iResult = m_isoReader.ReadFile( m_hFile, (BYTE*)pData, (long)uiBufSize);
if (iResult == -1)
return 0;
return iResult;
diff --git a/xbmc/filesystem/NFSFile.cpp b/xbmc/filesystem/NFSFile.cpp
index a7b49b3b57845..8f61878b8556e 100644
--- a/xbmc/filesystem/NFSFile.cpp
+++ b/xbmc/filesystem/NFSFile.cpp
@@ -140,6 +140,17 @@ void CNfsConnection::destroyOpenContexts()
m_openContextMap.clear();
}
+void CNfsConnection::destroyContext(const CStdString &exportName)
+{
+ CSingleLock lock(openContextLock);
+ tOpenContextMap::iterator it = m_openContextMap.find(exportName.c_str());
+ if(it != m_openContextMap.end())
+ {
+ m_pLibNfs->nfs_destroy_context(it->second.pContext);
+ m_openContextMap.erase(it);
+ }
+}
+
struct nfs_context *CNfsConnection::getContextFromMap(const CStdString &exportname, bool forceCacheHit/* = false*/)
{
struct nfs_context *pRet = NULL;
@@ -166,6 +177,7 @@ struct nfs_context *CNfsConnection::getContextFromMap(const CStdString &exportna
//destroy it and return NULL
CLog::Log(LOGDEBUG, "NFS: Old context timed out - destroying it");
m_pLibNfs->nfs_destroy_context(it->second.pContext);
+ m_openContextMap.erase(it);
}
}
return pRet;
@@ -288,6 +300,7 @@ bool CNfsConnection::Connect(const CURL& url, CStdString &relativePath)
if(nfsRet != 0)
{
CLog::Log(LOGERROR,"NFS: Failed to mount nfs share: %s (%s)\n", exportPath.c_str(), m_pLibNfs->nfs_get_error(m_pNfsContext));
+ destroyContext(url.GetHostName() + exportPath);
return false;
}
CLog::Log(LOGDEBUG,"NFS: Connected to server %s and export %s\n", url.GetHostName().c_str(), exportPath.c_str());
diff --git a/xbmc/filesystem/NFSFile.h b/xbmc/filesystem/NFSFile.h
index 7e2db95aa7c19..bd758e7117b2b 100644
--- a/xbmc/filesystem/NFSFile.h
+++ b/xbmc/filesystem/NFSFile.h
@@ -117,6 +117,7 @@ class CNfsConnection : public CCriticalSection
struct nfs_context *getContextFromMap(const CStdString &exportname, bool forceCacheHit = false);
int getContextForExport(const CStdString &exportname);//get context for given export and add to open contexts map - sets m_pNfsContext (my return a already mounted cached context)
void destroyOpenContexts();
+ void destroyContext(const CStdString &exportName);
void resolveHost(const CURL &url);//resolve hostname by dnslookup
void keepAlive(std::string _exportPath, struct nfsfh *_pFileHandle);
};
diff --git a/xbmc/filesystem/RarFile.h b/xbmc/filesystem/RarFile.h
index 5163c49e2be7f..de47391fbc4c2 100644
--- a/xbmc/filesystem/RarFile.h
+++ b/xbmc/filesystem/RarFile.h
@@ -104,8 +104,8 @@ namespace XFILE
CmdExtract* m_pExtract;
CRarFileExtractThread* m_pExtractThread;
#endif
- byte* m_szBuffer;
- byte* m_szStartOfBuffer;
+ BYTE* m_szBuffer;
+ BYTE* m_szStartOfBuffer;
int64_t m_iDataInBuffer;
int64_t m_iBufferStart;
};
diff --git a/xbmc/filesystem/SFTPFile.cpp b/xbmc/filesystem/SFTPFile.cpp
index d176969835a37..a6212dca1fb33 100644
--- a/xbmc/filesystem/SFTPFile.cpp
+++ b/xbmc/filesystem/SFTPFile.cpp
@@ -275,12 +275,14 @@ bool CSFTPSession::VerifyKnownHost(ssh_session session)
CLog::Log(LOGINFO, "SFTPSession: Server file was not found, creating a new one");
case SSH_SERVER_NOT_KNOWN:
CLog::Log(LOGINFO, "SFTPSession: Server unkown, we trust it for now");
+#if !defined(TARGET_ANDROID)
+//TODO: use a writable path and remove this.
if (ssh_write_knownhost(session) < 0)
{
CLog::Log(LOGERROR, "CSFTPSession: Failed to save host '%s'", strerror(errno));
return false;
}
-
+#endif
return true;
case SSH_SERVER_ERROR:
CLog::Log(LOGERROR, "SFTPSession: Failed to verify host '%s'", ssh_get_error(session));
diff --git a/xbmc/filesystem/iso9660.cpp b/xbmc/filesystem/iso9660.cpp
index 7f2ad2f8dd0d2..d2417cd8901ad 100644
--- a/xbmc/filesystem/iso9660.cpp
+++ b/xbmc/filesystem/iso9660.cpp
@@ -752,7 +752,7 @@ HANDLE iso9660::OpenFile(const char *filename)
pContext->m_dwCurrentBlock = m_searchpointer->Location;
pContext->m_dwFileSize = m_info.curr_filesize = fileinfo.nFileSizeLow;
- pContext->m_pBuffer = new byte[CIRC_BUFFER_SIZE * BUFFER_SIZE];
+ pContext->m_pBuffer = new BYTE[CIRC_BUFFER_SIZE * BUFFER_SIZE];
pContext->m_dwStartBlock = pContext->m_dwCurrentBlock;
pContext->m_dwFilePos = 0;
pContext->m_dwCircBuffBegin = 0;
@@ -791,7 +791,7 @@ void iso9660::CloseFile(HANDLE hFile)
FreeFileContext(hFile);
}
//************************************************************************************
-bool iso9660::ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, byte** ppBuffer)
+bool iso9660::ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, BYTE** ppBuffer)
{
DWORD StartSectorInCircBuff = pContext->m_dwCircBuffSectorStart;
@@ -891,7 +891,7 @@ void iso9660::ReleaseSectorFromCache(iso9660::isofile* pContext, DWORD sector)
}
}
//************************************************************************************
-long iso9660::ReadFile(HANDLE hFile, byte *pBuffer, long lSize)
+long iso9660::ReadFile(HANDLE hFile, BYTE *pBuffer, long lSize)
{
bool bError;
long iBytesRead = 0;
@@ -912,7 +912,7 @@ long iso9660::ReadFile(HANDLE hFile, byte *pBuffer, long lSize)
//sprintf(szBuf,"pos:%i cblk:%i sblk:%i off:%i",(long)m_dwFilePos, (long)m_dwCurrentBlock,(long)m_dwStartBlock,(long)iOffsetInBuffer);
//DBG(szBuf);
- byte* pSector;
+ BYTE* pSector;
bError = !ReadSectorFromCache(pContext, pContext->m_dwCurrentBlock, &pSector);
if (!bError)
{
diff --git a/xbmc/filesystem/iso9660.h b/xbmc/filesystem/iso9660.h
index e2989c8dfb787..bd3dbbc2000ca 100644
--- a/xbmc/filesystem/iso9660.h
+++ b/xbmc/filesystem/iso9660.h
@@ -185,7 +185,7 @@ class iso9660
int64_t GetFilePosition(HANDLE hFile);
int64_t Seek(HANDLE hFile, int64_t lOffset, int whence);
HANDLE OpenFile( const char* filename );
- long ReadFile(HANDLE fd, byte *pBuffer, long lSize);
+ long ReadFile(HANDLE fd, BYTE *pBuffer, long lSize);
void CloseFile(HANDLE hFile);
void Reset();
void Scan();
@@ -196,7 +196,7 @@ class iso9660
struct iso_dirtree* ReadRecursiveDirFromSector( DWORD sector, const char * );
struct iso_dirtree* FindFolder( char *Folder );
std::string GetThinText(BYTE* strTxt, int iLen );
- bool ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, byte** ppBuffer);
+ bool ReadSectorFromCache(iso9660::isofile* pContext, DWORD sector, BYTE** ppBuffer);
void ReleaseSectorFromCache(iso9660::isofile* pContext, DWORD sector);
const std::string ParseName(struct iso9660_Directory& isodir);
HANDLE AllocFileContext();
diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
index 8d04313047eee..7a96095f5903f 100644
--- a/xbmc/guilib/GUIShader.cpp
+++ b/xbmc/guilib/GUIShader.cpp
@@ -38,6 +38,7 @@ CGUIShader::CGUIShader( const char *shader ) : CGLSLShaderProgram("guishader_ver
m_hCol = 0;
m_hCord0 = 0;
m_hCord1 = 0;
+ m_hUniCol = 0;
m_proj = NULL;
m_model = NULL;
@@ -50,6 +51,8 @@ void CGUIShader::OnCompiledAndLinked()
// Variables passed directly to the Fragment shader
m_hTex0 = glGetUniformLocation(ProgramHandle(), "m_samp0");
m_hTex1 = glGetUniformLocation(ProgramHandle(), "m_samp1");
+ m_hUniCol = glGetUniformLocation(ProgramHandle(), "m_unicol");
+
// Variables passed directly to the Vertex shader
m_hProj = glGetUniformLocation(ProgramHandle(), "m_proj");
m_hModel = glGetUniformLocation(ProgramHandle(), "m_model");
@@ -62,6 +65,7 @@ void CGUIShader::OnCompiledAndLinked()
glUseProgram( ProgramHandle() );
glUniform1i(m_hTex0, 0);
glUniform1i(m_hTex1, 1);
+ glUniform4f(m_hUniCol, 1.0, 1.0, 1.0, 1.0);
glUseProgram( 0 );
}
diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
index d84e25158a0b2..95de7585e6656 100644
--- a/xbmc/guilib/GUIShader.h
+++ b/xbmc/guilib/GUIShader.h
@@ -39,10 +39,12 @@ class CGUIShader : public CGLSLShaderProgram
GLint GetColLoc() { return m_hCol; }
GLint GetCord0Loc() { return m_hCord0; }
GLint GetCord1Loc() { return m_hCord1; }
+ GLint GetUniColLoc() { return m_hUniCol; }
protected:
GLint m_hTex0;
GLint m_hTex1;
+ GLint m_hUniCol;
GLint m_hProj;
GLint m_hModel;
GLint m_hPos;
diff --git a/xbmc/guilib/GUITextureGLES.cpp b/xbmc/guilib/GUITextureGLES.cpp
index 86fb6bb3aaf1d..9621a89b56d6b 100644
--- a/xbmc/guilib/GUITextureGLES.cpp
+++ b/xbmc/guilib/GUITextureGLES.cpp
@@ -72,9 +72,6 @@ void CGUITextureGLES::Begin(color_t color)
m_diffuse.m_textures[0]->BindToUnit(1);
- GLint tex1Loc = g_Windowing.GUIShaderGetCoord1();
- glVertexAttribPointer(tex1Loc, 2, GL_FLOAT, 0, 0, m_tex1);
- glEnableVertexAttribArray(tex1Loc);
}
else
{
@@ -88,20 +85,6 @@ void CGUITextureGLES::Begin(color_t color)
}
}
- GLint posLoc = g_Windowing.GUIShaderGetPos();
- GLint colLoc = g_Windowing.GUIShaderGetCol();
- GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
-
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, m_vert);
- if(colLoc >= 0)
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, m_col);
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, 0, 0, m_tex0);
-
- glEnableVertexAttribArray(posLoc);
- if(colLoc >= 0)
- glEnableVertexAttribArray(colLoc);
- glEnableVertexAttribArray(tex0Loc);
-
if ( hasAlpha )
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
@@ -111,101 +94,136 @@ void CGUITextureGLES::Begin(color_t color)
{
glDisable(GL_BLEND);
}
+ m_packedVertices.clear();
}
void CGUITextureGLES::End()
{
+ GLint posLoc = g_Windowing.GUIShaderGetPos();
+ GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
+ GLint tex1Loc = g_Windowing.GUIShaderGetCoord1();
+ GLint uniColLoc = g_Windowing.GUIShaderGetUniCol();
+
+ if(uniColLoc >= 0)
+ {
+ glUniform4f(uniColLoc,(m_col[0][0] / 255.0), (m_col[0][1] / 255.0), (m_col[0][2] / 255.0), (m_col[0][3] / 255.0));
+ }
+
+ if(m_diffuse.size())
+ {
+ glVertexAttribPointer(tex1Loc, 2, GL_FLOAT, 0, sizeof(PackedVertex), (char*)&m_packedVertices[0] + offsetof(PackedVertex, u2));
+ glEnableVertexAttribArray(tex1Loc);
+ }
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, sizeof(PackedVertex), (char*)&m_packedVertices[0] + offsetof(PackedVertex, x));
+ glEnableVertexAttribArray(posLoc);
+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, 0, sizeof(PackedVertex), (char*)&m_packedVertices[0] + offsetof(PackedVertex, u1));
+ glEnableVertexAttribArray(tex0Loc);
+
+ GLushort *idx;
+ idx = new GLushort[m_packedVertices.size()*6 / 4];
+ for (unsigned int i=0, size=0; i < m_packedVertices.size(); i+=4, size+=6)
+ {
+ idx[size+0] = i+0;
+ idx[size+1] = i+1;
+ idx[size+2] = i+2;
+ idx[size+3] = i+2;
+ idx[size+4] = i+3;
+ idx[size+5] = i+0;
+ }
+
+ glDrawElements(GL_TRIANGLES, m_packedVertices.size()*6 / 4, GL_UNSIGNED_SHORT, idx);
+
if (m_diffuse.size())
{
- glDisableVertexAttribArray(g_Windowing.GUIShaderGetCoord1());
+ glDisableVertexAttribArray(tex1Loc);
glActiveTexture(GL_TEXTURE0);
}
- glDisableVertexAttribArray(g_Windowing.GUIShaderGetPos());
- GLint colLoc = g_Windowing.GUIShaderGetCol();
- if(colLoc >= 0)
- glDisableVertexAttribArray(g_Windowing.GUIShaderGetCol());
- glDisableVertexAttribArray(g_Windowing.GUIShaderGetCoord0());
+ glDisableVertexAttribArray(posLoc);
+ glDisableVertexAttribArray(tex0Loc);
glEnable(GL_BLEND);
g_Windowing.DisableGUIShader();
+ delete [] idx;
}
void CGUITextureGLES::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, int orientation)
{
- GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
-
- // Setup vertex position values
- for (int i=0; i<4; i++)
- {
- m_vert[i][0] = x[i];
- m_vert[i][1] = y[i];
- m_vert[i][2] = z[i];
- }
+ PackedVertex vertices[4];
// Setup texture coordinates
//TopLeft
- m_tex0[0][0] = texture.x1;
- m_tex0[0][1] = texture.y1;
+ vertices[0].u1 = texture.x1;
+ vertices[0].v1 = texture.y1;
//TopRight
if (orientation & 4)
{
- m_tex0[1][0] = texture.x1;
- m_tex0[1][1] = texture.y2;
+ vertices[1].u1 = texture.x1;
+ vertices[1].v1 = texture.y2;
}
else
{
- m_tex0[1][0] = texture.x2;
- m_tex0[1][1] = texture.y1;
+ vertices[1].u1 = texture.x2;
+ vertices[1].v1 = texture.y1;
}
//BottomRight
- m_tex0[2][0] = texture.x2;
- m_tex0[2][1] = texture.y2;
+ vertices[2].u1 = texture.x2;
+ vertices[2].v1 = texture.y2;
//BottomLeft
if (orientation & 4)
{
- m_tex0[3][0] = texture.x2;
- m_tex0[3][1] = texture.y1;
+ vertices[3].u1 = texture.x2;
+ vertices[3].v1 = texture.y1;
}
else
{
- m_tex0[3][0] = texture.x1;
- m_tex0[3][1] = texture.y2;
+ vertices[3].u1 = texture.x1;
+ vertices[3].v1 = texture.y2;
}
if (m_diffuse.size())
{
//TopLeft
- m_tex1[0][0] = diffuse.x1;
- m_tex1[0][1] = diffuse.y1;
+ vertices[0].u2 = diffuse.x1;
+ vertices[0].v2 = diffuse.y1;
//TopRight
if (m_info.orientation & 4)
{
- m_tex1[1][0] = diffuse.x1;
- m_tex1[1][1] = diffuse.y2;
+ vertices[1].u2 = diffuse.x1;
+ vertices[1].v2 = diffuse.y2;
}
else
{
- m_tex1[1][0] = diffuse.x2;
- m_tex1[1][1] = diffuse.y1;
+ vertices[1].u2 = diffuse.x2;
+ vertices[1].v2 = diffuse.y1;
}
//BottomRight
- m_tex1[2][0] = diffuse.x2;
- m_tex1[2][1] = diffuse.y2;
+ vertices[2].u2 = diffuse.x2;
+ vertices[2].v2 = diffuse.y2;
//BottomLeft
if (m_info.orientation & 4)
{
- m_tex1[3][0] = diffuse.x2;
- m_tex1[3][1] = diffuse.y1;
+ vertices[3].u2 = diffuse.x2;
+ vertices[3].v2 = diffuse.y1;
}
else
{
- m_tex1[3][0] = diffuse.x1;
- m_tex1[3][1] = diffuse.y2;
+ vertices[3].u2 = diffuse.x1;
+ vertices[3].v2 = diffuse.y2;
}
}
- glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
+ for (int i=0; i<4; i++)
+ {
+ vertices[i].x = x[i];
+ vertices[i].y = y[i];
+ vertices[i].z = z[i];
+ vertices[i].r = m_col[i][0];
+ vertices[i].g = m_col[i][1];
+ vertices[i].b = m_col[i][2];
+ vertices[i].a = m_col[i][3];
+ m_packedVertices.push_back(vertices[i]);
+ }
}
void CGUITextureGLES::DrawQuad(const CRect &rect, color_t color, CBaseTexture *texture, const CRect *texCoords)
@@ -234,6 +252,7 @@ void CGUITextureGLES::DrawQuad(const CRect &rect, color_t color, CBaseTexture *t
GLint posLoc = g_Windowing.GUIShaderGetPos();
GLint colLoc = g_Windowing.GUIShaderGetCol();
GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
+ GLint uniColLoc= g_Windowing.GUIShaderGetUniCol();
glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, ver);
if(colLoc >= 0)
@@ -256,6 +275,8 @@ void CGUITextureGLES::DrawQuad(const CRect &rect, color_t color, CBaseTexture *t
col[i][3] = (GLubyte)GET_A(color);
}
+ glUniform4f(uniColLoc,col[0][0] / 255, col[0][1] / 255, col[0][2] / 255, col[0][3] / 255);
+
// Setup vertex position values
#define ROUND_TO_PIXEL(x) (float)(MathUtils::round_int(x))
ver[0][0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(rect.x1, rect.y1));
diff --git a/xbmc/guilib/GUITextureGLES.h b/xbmc/guilib/GUITextureGLES.h
index d0d38dfc08a4a..206d9d6427280 100644
--- a/xbmc/guilib/GUITextureGLES.h
+++ b/xbmc/guilib/GUITextureGLES.h
@@ -32,6 +32,15 @@
#include "system_gl.h"
+struct PackedVertex
+{
+ float x, y, z;
+ unsigned char r, g, b, a;
+ float u1, v1;
+ float u2, v2;
+};
+typedef std::vector PackedVertices;
+
class CGUITextureGLES : public CGUITextureBase
{
public:
@@ -43,9 +52,8 @@ class CGUITextureGLES : public CGUITextureBase
void End();
GLubyte m_col [4][4];
- GLfloat m_vert[4][3];
- GLfloat m_tex0[4][2];
- GLfloat m_tex1[4][2];
+
+ PackedVertices m_packedVertices;
};
#endif
diff --git a/xbmc/guilib/GUIVideoControl.cpp b/xbmc/guilib/GUIVideoControl.cpp
index f9c7090729785..49e1a0fe7b69d 100644
--- a/xbmc/guilib/GUIVideoControl.cpp
+++ b/xbmc/guilib/GUIVideoControl.cpp
@@ -40,7 +40,8 @@ CGUIVideoControl::~CGUIVideoControl(void)
void CGUIVideoControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
{
// TODO Proper processing which marks when its actually changed. Just mark always for now.
- MarkDirtyRegion();
+ if (g_renderManager.RendererHandlesPresent())
+ MarkDirtyRegion();
CGUIControl::Process(currentTime, dirtyregions);
}
diff --git a/xbmc/guilib/Key.h b/xbmc/guilib/Key.h
index 10aa356f06f73..be24f7fad7ea4 100644
--- a/xbmc/guilib/Key.h
+++ b/xbmc/guilib/Key.h
@@ -314,7 +314,7 @@
#define ACTION_SUBTITLE_ALIGN 232 // toggle vertical alignment of subtitles
#define ACTION_FILTER 233
-
+#define ACTION_CONNECTIONS_REFRESH 300
// Window ID defines to make the code a bit more readable
#define WINDOW_INVALID 9999
#define WINDOW_HOME 10000
diff --git a/xbmc/input/linux/LinuxInputDevices.cpp b/xbmc/input/linux/LinuxInputDevices.cpp
index f4331658c46af..c43fd2bb4283f 100644
--- a/xbmc/input/linux/LinuxInputDevices.cpp
+++ b/xbmc/input/linux/LinuxInputDevices.cpp
@@ -782,7 +782,7 @@ void CLinuxInputDevice::SetupKeyboardAutoRepeat(int fd)
{
bool enable = true;
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
// ignore the native aml driver named 'key_input',
// it is the dedicated power key handler (am_key_input)
if (strncmp(m_deviceName, "key_input", strlen("key_input")) == 0)
@@ -967,7 +967,6 @@ bool CLinuxInputDevices::CheckDevice(const char *device)
{
int fd;
- CLog::Log(LOGDEBUG, "Checking device: %s\n", device);
/* Check if we are able to open the device */
fd = open(device, O_RDWR);
if (fd < 0)
diff --git a/xbmc/interfaces/Builtins.cpp b/xbmc/interfaces/Builtins.cpp
index fae25240a3e55..066d142a40924 100644
--- a/xbmc/interfaces/Builtins.cpp
+++ b/xbmc/interfaces/Builtins.cpp
@@ -18,7 +18,6 @@
*
*/
-#include "network/Network.h"
#include "system.h"
#include "utils/AlarmClock.h"
#include "utils/Screenshot.h"
@@ -1261,8 +1260,8 @@ int CBuiltins::Execute(const CStdString& execString)
g_application.StopVideoScan();
ADDON::CAddonMgr::Get().StopServices(true);
+ g_application.getNetworkManager().NetworkMessage(CNetworkManager::SERVICES_DOWN,1);
- g_application.getNetwork().NetworkMessage(CNetwork::SERVICES_DOWN,1);
g_settings.LoadMasterForLogin();
g_passwordManager.bMasterUser = false;
g_windowManager.ActivateWindow(WINDOW_LOGIN_SCREEN);
@@ -1517,7 +1516,7 @@ int CBuiltins::Execute(const CStdString& execString)
}
else if (execute.Equals("wakeonlan"))
{
- g_application.getNetwork().WakeOnLan((char*)params[0].c_str());
+ g_application.getNetworkManager().WakeOnLan((char*)params[0].c_str());
}
else if (execute.Equals("addon.default.opensettings") && params.size() == 1)
{
diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp
index f995a2f6ce607..2009a0ab90281 100644
--- a/xbmc/interfaces/legacy/ModuleXbmc.cpp
+++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp
@@ -24,7 +24,6 @@
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
-#include "network/Network.h"
#include "ModuleXbmc.h"
@@ -189,13 +188,7 @@ namespace XBMCAddon
String getIPAddress()
{
TRACE;
- char cTitleIP[32];
- sprintf(cTitleIP, "127.0.0.1");
- CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
- if (iface)
- return iface->GetCurrentIPAddress();
-
- return cTitleIP;
+ return g_application.getNetworkManager().GetDefaultConnectionAddress().c_str();
}
long getDVDState()
diff --git a/xbmc/interfaces/python/CallbackHandler.cpp b/xbmc/interfaces/python/CallbackHandler.cpp
index 01707b964a68d..1bb3997a4c76f 100644
--- a/xbmc/interfaces/python/CallbackHandler.cpp
+++ b/xbmc/interfaces/python/CallbackHandler.cpp
@@ -36,7 +36,6 @@ namespace XBMCAddon
PythonCallbackHandler::PythonCallbackHandler() : RetardedAsynchCallbackHandler("PythonCallbackHandler")
{
objectThreadState = PyThreadState_Get();
- CLog::Log(LOGDEBUG,"NEWADDON PythonCallbackHandler construction with PyThreadState 0x%lx",(long)objectThreadState);
}
/**
diff --git a/xbmc/linux/PlatformDefs.h b/xbmc/linux/PlatformDefs.h
index a66ef0adee49e..07f91e1bba67e 100644
--- a/xbmc/linux/PlatformDefs.h
+++ b/xbmc/linux/PlatformDefs.h
@@ -155,7 +155,6 @@
#define ZeroMemory(dst,size) memset(dst, 0, size)
#define VOID void
-#define byte unsigned char
#define __int8 char
#define __int16 short
#define __int32 int
diff --git a/xbmc/linux/PosixMountProvider.cpp b/xbmc/linux/PosixMountProvider.cpp
index c91a76e403a7a..27d639eee538a 100644
--- a/xbmc/linux/PosixMountProvider.cpp
+++ b/xbmc/linux/PosixMountProvider.cpp
@@ -65,6 +65,7 @@ void CPosixMountProvider::GetDrives(VECSOURCES &drives)
|| strcmp(fs, "ext2") == 0 || strcmp(fs, "ext3") == 0
|| strcmp(fs, "reiserfs") == 0 || strcmp(fs, "xfs") == 0
|| strcmp(fs, "ntfs-3g") == 0 || strcmp(fs, "iso9660") == 0
+ || strcmp(fs, "exfat") == 0
|| strcmp(fs, "fusefs") == 0 || strcmp(fs, "hfs") == 0)
accepted = true;
@@ -126,6 +127,16 @@ std::vector CPosixMountProvider::GetDiskUsage()
return result;
}
+bool CPosixMountProvider::Eject(CStdString mountpath)
+{
+ // just go ahead and try to umount the disk
+ // if it does umount, life is good, if not, no loss.
+ std::string cmd = "umount " + mountpath;
+ system(cmd.c_str());
+
+ return true;
+}
+
bool CPosixMountProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
{
VECSOURCES drives;
diff --git a/xbmc/linux/PosixMountProvider.h b/xbmc/linux/PosixMountProvider.h
index da0506cdf4316..02ff302172957 100644
--- a/xbmc/linux/PosixMountProvider.h
+++ b/xbmc/linux/PosixMountProvider.h
@@ -34,7 +34,7 @@ class CPosixMountProvider : public IStorageProvider
virtual std::vector GetDiskUsage();
- virtual bool Eject(CStdString mountpath) { return false; }
+ virtual bool Eject(CStdString mountpath);
virtual bool PumpDriveChangeEvents(IStorageEventsCallback *callback);
private:
diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp
index bdee61aca872d..c387ddea5eeab 100644
--- a/xbmc/music/MusicDatabase.cpp
+++ b/xbmc/music/MusicDatabase.cpp
@@ -18,7 +18,6 @@
*
*/
-#include "network/Network.h"
#include "threads/SystemClock.h"
#include "system.h"
#include "MusicDatabase.h"
@@ -2390,7 +2389,7 @@ bool CMusicDatabase::LookupCDDBInfo(bool bRequery/*=false*/)
return false;
// check network connectivity
- if (!g_application.getNetwork().IsAvailable())
+ if (!g_application.getNetworkManager().IsAvailable())
return false;
// Get information for the inserted disc
diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp
index fd7f755a558a2..866728c7b120a 100644
--- a/xbmc/network/AirPlayServer.cpp
+++ b/xbmc/network/AirPlayServer.cpp
@@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "network/Network.h"
#include "AirPlayServer.h"
#ifdef HAS_AIRPLAY
@@ -119,7 +118,7 @@ const char *eventStrings[] = {"playing", "paused", "loading", "stopped"};
"features\r\n"\
"119\r\n"\
"model\r\n"\
-"AppleTV2,1\r\n"\
+"Xbmc,1\r\n"\
"protovers\r\n"\
"1.0\r\n"\
"srcvers\r\n"\
@@ -960,7 +959,7 @@ int CAirPlayServer::CTCPClient::ProcessRequest( CStdString& responseHeader,
else if (uri == "/server-info")
{
CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str());
- responseBody.Format(SERVER_INFO, g_application.getNetwork().GetFirstConnectedInterface()->GetMacAddress());
+ responseBody.Format(SERVER_INFO, g_application.getNetworkManager().GetDefaultConnectionMacAddress());
responseHeader = "Content-Type: text/x-apple-plist+xml\r\n";
}
diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp
index 8af8319ee5a7c..95a43c1bf0be8 100644
--- a/xbmc/network/AirTunesServer.cpp
+++ b/xbmc/network/AirTunesServer.cpp
@@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "network/Network.h"
#if !defined(TARGET_WINDOWS)
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif
@@ -148,6 +147,7 @@ LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ\
void CAirTunesServer::AudioOutputFunctions::audio_set_metadata(void *cls, void *session, const void *buffer, int buflen)
{
+ return;
CAirTunesServer::SetMetadataFromBuffer((char *)buffer, buflen);
}
@@ -339,7 +339,11 @@ ao_device* CAirTunesServer::AudioOutputFunctions::ao_open_live(int driver_id, ao
header.durationMs = 0;
if (device->pipe->Write(&header, sizeof(header)) == 0)
+ {
+ delete device->pipe;
+ delete device;
return 0;
+ }
ThreadMessage tMsg = { TMSG_MEDIA_STOP };
CApplicationMessenger::Get().SendMessage(tMsg, true);
@@ -468,21 +472,13 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
{
bool success = false;
CStdString pw = password;
- CNetworkInterface *net = g_application.getNetwork().GetFirstConnectedInterface();
StopServer(true);
- if (net)
- {
- m_macAddress = net->GetMacAddress();
- m_macAddress.Replace(":","");
- while (m_macAddress.size() < 12)
- {
- m_macAddress = CStdString("0") + m_macAddress;
- }
- }
- else
+ m_macAddress = g_application.getNetworkManager().GetDefaultConnectionMacAddress();
+ m_macAddress.Replace(":","");
+ while (m_macAddress.size() < 12)
{
- m_macAddress = "000102030405";
+ m_macAddress = CStdString("0") + m_macAddress;
}
if (!usePassword)
@@ -504,22 +500,23 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
CStdString appName;
appName.Format("%s@%s", m_macAddress.c_str(), g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME).c_str());
- std::map txt;
- txt["cn"] = "0,1";
- txt["ch"] = "2";
- txt["ek"] = "1";
- txt["et"] = "0,1";
- txt["sv"] = "false";
- txt["tp"] = "UDP";
- txt["sm"] = "false";
- txt["ss"] = "16";
- txt["sr"] = "44100";
- txt["pw"] = "false";
- txt["vn"] = "3";
- txt["da"] = "true";
- txt["vs"] = "130.14";
- txt["md"] = "0,1,2";
- txt["txtvers"] = "1";
+ std::vector > txt;
+ txt.push_back(std::make_pair("txtvers", "1"));
+ txt.push_back(std::make_pair("cn", "0,1"));
+ txt.push_back(std::make_pair("ch", "2"));
+ txt.push_back(std::make_pair("ek", "1"));
+ txt.push_back(std::make_pair("et", "0,1"));
+ txt.push_back(std::make_pair("sv", "false"));
+ txt.push_back(std::make_pair("tp", "UDP"));
+ txt.push_back(std::make_pair("sm", "false"));
+ txt.push_back(std::make_pair("ss", "16"));
+ txt.push_back(std::make_pair("sr", "44100"));
+ txt.push_back(std::make_pair("pw", "false"));
+ txt.push_back(std::make_pair("vn", "3"));
+ txt.push_back(std::make_pair("da", "true"));
+ txt.push_back(std::make_pair("vs", "130.14"));
+ txt.push_back(std::make_pair("md", "0,1,2"));
+ txt.push_back(std::make_pair("am", "Xbmc,1"));
CZeroconf::GetInstance()->PublishService("servers.airtunes", "_raop._tcp", appName, port, txt);
}
@@ -658,7 +655,7 @@ bool CAirTunesServer::Initialize(const CStdString &password)
if (m_pLibShairport->Load())
{
- struct AudioOutput ao;
+ struct AudioOutput ao = {0};
ao.ao_initialize = AudioOutputFunctions::ao_initialize;
ao.ao_play = AudioOutputFunctions::ao_play;
ao.ao_default_driver_id = AudioOutputFunctions::ao_default_driver_id;
diff --git a/xbmc/network/ConnectionJob.cpp b/xbmc/network/ConnectionJob.cpp
new file mode 100644
index 0000000000000..c46ac336cb761
--- /dev/null
+++ b/xbmc/network/ConnectionJob.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "ConnectionJob.h"
+#include "Application.h"
+#include "utils/log.h"
+#include "dialogs/GUIDialogOK.h"
+#include "dialogs/GUIDialogBusy.h"
+#include "guilib/GUIKeyboardFactory.h"
+#include "guilib/GUIWindowManager.h"
+#include "security/KeyringManager.h"
+#include "settings/GUISettings.h"
+#include "settings/AdvancedSettings.h"
+
+CConnectionJob::CConnectionJob(CConnectionPtr connection, const CIPConfig &ipconfig, CKeyringManager *keyringManager)
+{
+ m_ipconfig = ipconfig;
+ m_connection = connection;
+ m_keyringManager = keyringManager;
+}
+
+bool CConnectionJob::DoWork()
+{
+ bool result;
+
+ CGUIDialogBusy *busy_dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY);
+ busy_dialog->Show();
+
+ // we need to shutdown network services before changing the connection.
+ // The Network Manager's PumpNetworkEvents will take care of starting them back up.
+ g_application.getNetworkManager().OnConnectionStateChange(NETWORK_CONNECTION_STATE_DISCONNECTED);
+ result = m_connection->Connect((IPassphraseStorage*)this, m_ipconfig);
+ if (!result)
+ {
+ // the connect failed, pop a failed dialog
+ // and revert to the previous connection.
+ // Not connected. Check network settings.
+ CGUIDialogOK::ShowAndGetInput(0, 13297, 0, 0);
+ }
+
+ busy_dialog->Close();
+ return result;
+}
+
+void CConnectionJob::InvalidatePassphrase(const std::string &uuid)
+{
+ m_keyringManager->EraseSecret("network", uuid);
+ g_guiSettings.SetString("network.passphrase", "");
+}
+
+bool CConnectionJob::GetPassphrase(const std::string &uuid, std::string &passphrase)
+{
+ passphrase = g_guiSettings.GetString("network.passphrase");
+ if (passphrase.size() > 0)
+ return true;
+ /*
+ CVariant secret;
+ if (m_keyringManager->FindSecret("network", uuid, secret) && secret.isString())
+ {
+ passphrase = secret.asString();
+ return true;
+ }
+ */
+ else
+ {
+ bool result;
+ CStdString utf8;
+ if (g_advancedSettings.m_showNetworkPassPhrase)
+ result = CGUIKeyboardFactory::ShowAndGetInput(utf8, 12340, false);
+ else
+ result = CGUIKeyboardFactory::ShowAndGetNewPassword(utf8);
+
+ passphrase = utf8;
+ StorePassphrase(uuid, passphrase);
+ return result;
+ }
+}
+
+void CConnectionJob::StorePassphrase(const std::string &uuid, const std::string &passphrase)
+{
+ m_keyringManager->StoreSecret("network", uuid, CVariant(passphrase));
+ // hack until we get keyring storage working
+ g_guiSettings.SetString("network.passphrase", passphrase.c_str());
+}
diff --git a/xbmc/network/ConnectionJob.h b/xbmc/network/ConnectionJob.h
new file mode 100644
index 0000000000000..687a4fa681510
--- /dev/null
+++ b/xbmc/network/ConnectionJob.h
@@ -0,0 +1,43 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2010 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "IConnection.h"
+#include "utils/Job.h"
+
+class CKeyringManager;
+
+class CConnectionJob : public CJob, public IPassphraseStorage
+{
+public:
+ CConnectionJob(CConnectionPtr connection, const CIPConfig &ipconfig, CKeyringManager *keyringManager);
+
+ virtual bool DoWork();
+
+ virtual void InvalidatePassphrase(const std::string &uuid);
+ virtual bool GetPassphrase(const std::string &uuid, std::string &passphrase);
+ virtual void StorePassphrase(const std::string &uuid, const std::string &passphrase);
+private:
+ CIPConfig m_ipconfig;
+ CConnectionPtr m_connection;
+ CKeyringManager *m_keyringManager;
+};
diff --git a/xbmc/network/EventServer.cpp b/xbmc/network/EventServer.cpp
index b4fd8c437157c..beb6c79bafc01 100644
--- a/xbmc/network/EventServer.cpp
+++ b/xbmc/network/EventServer.cpp
@@ -155,7 +155,7 @@ void CEventServer::Run()
CAddress any_addr;
CSocketListener listener;
int packetSize = 0;
- std::map txt;
+ std::vector > txt;
CLog::Log(LOGNOTICE, "ES: Starting UDP Event server on %s:%d", any_addr.Address(), m_iPort);
diff --git a/xbmc/network/GUIDialogAccessPoints.cpp b/xbmc/network/GUIDialogAccessPoints.cpp
index e04d276357a81..e454e73bc3791 100644
--- a/xbmc/network/GUIDialogAccessPoints.cpp
+++ b/xbmc/network/GUIDialogAccessPoints.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Team XBMC
+ * Copyright (C) 2011-2012 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -13,120 +13,298 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
*
*/
#include "GUIDialogAccessPoints.h"
-#include "guilib/GUIKeyboardFactory.h"
-#ifdef _LINUX
-#include "linux/NetworkLinux.h"
-#endif
+#include "dialogs/GUIDialogKeyboardGeneric.h"
#include "Application.h"
+#include "ApplicationMessenger.h"
#include "FileItem.h"
#include "guilib/LocalizeStrings.h"
+#include "guilib/GUIWindowManager.h"
+#include "utils/JobManager.h"
+#include "ConnectionJob.h"
-#define CONTROL_ACCESS_POINTS 3
+// defines for the controls
+#define ACCESS_POINT_LABEL 1
+#define ACCESS_POINT_LIST 3
+//--------------------------------------------------------------
+const std::string EncodeAccessPointParam(const std::string name, const CIPConfig &ipconfig)
+{
+ // encode CIPConfig structure into a string based ip connect param.
+ std::string method("dhcp");
+ if (ipconfig.m_method == IP_CONFIG_STATIC)
+ method = "static";
+
+ // '+' and '\t' are invalid essid characters,
+ // a ' ' is valid so watch out for those in the name.
+ const std::string param("name+" + name + "\t" +
+ "method+" + method + "\t" +
+ "address+" + ipconfig.m_address + "\t" +
+ "netmask+" + ipconfig.m_netmask + "\t" +
+ "gateway+" + ipconfig.m_gateway + "\t" +
+ "nameserver+" + ipconfig.m_nameserver + "\t");
+ return param;
+}
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
CGUIDialogAccessPoints::CGUIDialogAccessPoints(void)
: CGUIDialog(WINDOW_DIALOG_ACCESS_POINTS, "DialogAccessPoints.xml")
{
- m_accessPoints = new CFileItemList;
+ m_connectionsFileList = new CFileItemList;
}
CGUIDialogAccessPoints::~CGUIDialogAccessPoints(void)
{
- delete m_accessPoints;
+ delete m_connectionsFileList;
}
bool CGUIDialogAccessPoints::OnAction(const CAction &action)
{
if (action.GetID() == ACTION_SELECT_ITEM)
{
- CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_ACCESS_POINTS);
- OnMessage(msg);
- int iItem = msg.GetParam1();
+ // block users from doing another connection
+ // while we are already trying to connect.
+ if (!m_doing_connection)
+ {
+ // fetch the current selected item (access point)
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), ACCESS_POINT_LIST);
+ OnMessage(msg);
+ int iItem = msg.GetParam1();
+
+ ConnectionList connections = g_application.getNetworkManager().GetConnections();
+ CConnectionJob *connection = new CConnectionJob(connections[iItem],
+ m_ipconfig, &g_application.getKeyringManager());
+ CJobManager::GetInstance().AddJob(connection, this);
+ m_doing_connection = true;
+ }
+ return true;
+ }
+ else if (action.GetID() == ACTION_CONNECTIONS_REFRESH)
+ {
+ // msg from Network Manager when the network connection changes.
+ // this is for future support for scanning for new access points.
+ UpdateConnectionList();
+ return true;
+ }
- if (iItem == (int) m_aps.size())
+ return CGUIDialog::OnAction(action);
+}
+
+bool CGUIDialogAccessPoints::OnMessage(CGUIMessage& message)
+{
+ bool result = CGUIDialog::OnMessage(message);
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_WINDOW_INIT:
{
- m_selectedAPEssId = "";
- if (CGUIKeyboardFactory::ShowAndGetInput(m_selectedAPEssId, g_localizeStrings.Get(789), false))
- {
- m_selectedAPEncMode = m_aps[iItem].getEncryptionMode();
- m_wasItemSelected = true;
- Close();
- return true;
- }
+ m_use_ipconfig = false;
+ m_doing_connection = false;
+ // fetch the param list
+ std::string param(message.GetStringParam());
+
+ // network apply vs network connect
+ if (param.find("name+") != std::string::npos)
+ {
+ m_use_ipconfig = true;
+ // network apply, param contains a description for connecting
+ // to an access point. we want to find this access point,
+ // disable the others, then inject a OnAction msg to select it.
+ DecodeAccessPointParam(param);
+ // change the label to show we are doing a connection.
+ CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), ACCESS_POINT_LABEL);
+ // Connecting
+ msg.SetLabel(g_localizeStrings.Get(33203));
+ OnMessage(msg);
+ }
+ UpdateConnectionList();
+ // if we are doing an 'apply', then inject a click on the "selected" item.
+ if (m_use_ipconfig)
+ CApplicationMessenger::Get().SendAction(CAction(ACTION_SELECT_ITEM), GetID());
+ break;
}
- else
+ case GUI_MSG_WINDOW_DEINIT:
{
- m_selectedAPEssId = m_aps[iItem].getEssId();
- m_selectedAPEncMode = m_aps[iItem].getEncryptionMode();
- m_wasItemSelected = true;
- Close();
- return true;
}
}
- return CGUIDialog::OnAction(action);
+ return result;
}
-void CGUIDialogAccessPoints::OnInitWindow()
+bool CGUIDialogAccessPoints::OnBack(int actionID)
{
- m_wasItemSelected = false;
+ // block the user from closing us if we are trying to connect.
+ if (m_doing_connection)
+ return false;
+ else
+ return CGUIDialog::OnBack(actionID);
+}
- CGUIDialog::OnInitWindow();
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+void CGUIDialogAccessPoints::OnJobComplete(unsigned int jobID, bool success, CJob *job)
+{
+ // auto-close when connection job completes
+ m_doing_connection = false;
+ if (success)
+ {
+ Close(true);
+ }
+}
- CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_ACCESS_POINTS);
- OnMessage(msgReset);
+void CGUIDialogAccessPoints::UpdateConnectionList()
+{
+ m_connectionsFileList->Clear();
- m_accessPoints->Clear();
+ CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), ACCESS_POINT_LIST);
+ OnMessage(msgReset);
- CStdString ifaceName(m_interfaceName);
- CNetworkInterface* iface = g_application.getNetwork().GetInterfaceByName(ifaceName);
- m_aps = iface->GetAccessPoints();
+ int connectedItem = 0;
+ ConnectionList connections = g_application.getNetworkManager().GetConnections();
- for (int i = 0; i < (int) m_aps.size(); i++)
+ std::string connection_name;
+ for (size_t i = 0; i < connections.size(); i++)
{
- CFileItemPtr item(new CFileItem(m_aps[i].getEssId()));
+ connection_name = connections[i]->GetName();
+ CFileItemPtr item(new CFileItem(connection_name));
- int q = m_aps[i].getQuality();
- if (q <= 20) item->SetArt("thumb", "ap-signal1.png");
- else if (q <= 40) item->SetArt("thumb", "ap-signal2.png");
- else if (q <= 60) item->SetArt("thumb", "ap-signal3.png");
- else if (q <= 80) item->SetArt("thumb", "ap-signal4.png");
- else if (q <= 100) item->SetArt("thumb", "ap-signal5.png");
+ if (m_use_ipconfig)
+ {
+ if (connection_name.find(m_ipname) != std::string::npos)
+ connectedItem = i;
+ }
+ else
+ {
+ if (connections[i]->GetState() == NETWORK_CONNECTION_STATE_CONNECTED)
+ connectedItem = i;
+ }
+ if (connections[i]->GetType() == NETWORK_CONNECTION_TYPE_WIFI)
+ {
+ int signal, strength = connections[i]->GetStrength();
+ if (strength == 0 || strength < 20)
+ signal = 1;
+ else if (strength == 20 || strength < 40)
+ signal = 2;
+ else if (strength == 40 || strength < 60)
+ signal = 3;
+ else if (strength == 60 || strength < 80)
+ signal = 4;
+ else
+ signal = 5;
- if (m_aps[i].getEncryptionMode() != ENC_NONE)
- item->SetIconImage("ap-lock.png");
+ if (strength <= 20) item->SetArt("thumb", "ap-signal1.png");
+ else if (strength <= 40) item->SetArt("thumb", "ap-signal2.png");
+ else if (strength <= 60) item->SetArt("thumb", "ap-signal3.png");
+ else if (strength <= 80) item->SetArt("thumb", "ap-signal4.png");
+ else if (strength <= 100) item->SetArt("thumb", "ap-signal5.png");
- m_accessPoints->Add(item);
- }
+ item->SetProperty("signal", signal);
+ item->SetProperty("encryption", EncryptionToString(connections[i]->GetEncryption()));
+ }
- CFileItemPtr item(new CFileItem(g_localizeStrings.Get(1047)));
- m_accessPoints->Add(item);
+ item->SetProperty("type", ConnectionTypeToString(connections[i]->GetType()));
+ item->SetProperty("state", ConnectionStateToString(connections[i]->GetState()));
+
+ m_connectionsFileList->Add(item);
+ }
- CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_ACCESS_POINTS, 0, 0, m_accessPoints);
+ CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), ACCESS_POINT_LIST, connectedItem, 0, m_connectionsFileList);
OnMessage(msg);
}
-void CGUIDialogAccessPoints::SetInterfaceName(CStdString interfaceName)
+void CGUIDialogAccessPoints::DecodeAccessPointParam(const std::string ¶m)
{
- m_interfaceName = interfaceName;
+ // decode a string based ip connect param into a CIPConfig structure.
+ std::string::size_type start;
+ std::string::size_type end;
+
+ start = param.find("name+") + sizeof("name");
+ end = param.find("\t", start);
+ m_ipname = param.substr(start, end - start);
+ //
+ start = param.find("method+") + sizeof("method");
+ end = param.find("\t", start);
+ m_ipconfig.m_method = IP_CONFIG_DHCP;
+ if (param.find("static", start) != std::string::npos)
+ m_ipconfig.m_method = IP_CONFIG_STATIC;
+ //
+ start = param.find("address+") + sizeof("address");
+ end = param.find("\t", start);
+ m_ipconfig.m_address = param.substr(start, end - start);
+ //
+ start = param.find("netmask+") + sizeof("netmask");
+ end = param.find("\t", start);
+ m_ipconfig.m_netmask = param.substr(start, end - start);
+ //
+ start = param.find("gateway+") + sizeof("gateway");
+ end = param.find("\t", start);
+ m_ipconfig.m_gateway = param.substr(start, end - start);
+ //
+ start = param.find("nameserver+") + sizeof("nameserver");
+ end = param.find("\t", start);
+ m_ipconfig.m_nameserver = param.substr(start, end - start);
}
-CStdString CGUIDialogAccessPoints::GetSelectedAccessPointEssId()
+const char *CGUIDialogAccessPoints::ConnectionStateToString(ConnectionState state)
{
- return m_selectedAPEssId;
+ switch (state)
+ {
+ case NETWORK_CONNECTION_STATE_DISCONNECTED:
+ return "disconnected";
+ case NETWORK_CONNECTION_STATE_CONNECTING:
+ return "connecting";
+ case NETWORK_CONNECTION_STATE_CONNECTED:
+ return "connected";
+ case NETWORK_CONNECTION_STATE_FAILURE:
+ return "failure";
+ case NETWORK_CONNECTION_STATE_UNKNOWN:
+ default:
+ return "unknown";
+ }
+
+ return "";
}
-EncMode CGUIDialogAccessPoints::GetSelectedAccessPointEncMode()
+const char *CGUIDialogAccessPoints::ConnectionTypeToString(ConnectionType type)
{
- return m_selectedAPEncMode;
+ switch (type)
+ {
+ case NETWORK_CONNECTION_TYPE_WIRED:
+ return "wired";
+ case NETWORK_CONNECTION_TYPE_WIFI:
+ return "wifi";
+ case NETWORK_CONNECTION_TYPE_UNKNOWN:
+ default:
+ return "unknown";
+ }
+
+ return "";
}
-bool CGUIDialogAccessPoints::WasItemSelected()
+const char *CGUIDialogAccessPoints::EncryptionToString(EncryptionType type)
{
- return m_wasItemSelected;
+ switch (type)
+ {
+ case NETWORK_CONNECTION_ENCRYPTION_NONE:
+ return "";
+ case NETWORK_CONNECTION_ENCRYPTION_WEP:
+ return "wep";
+ case NETWORK_CONNECTION_ENCRYPTION_WPA:
+ return "wpa";
+ case NETWORK_CONNECTION_ENCRYPTION_WPA2:
+ return "wpa2";
+ case NETWORK_CONNECTION_ENCRYPTION_IEEE8021x:
+ return "wpa-rsn";
+ case NETWORK_CONNECTION_ENCRYPTION_UNKNOWN:
+ default:
+ return "unknown";
+ }
+
+ return "";
}
diff --git a/xbmc/network/GUIDialogAccessPoints.h b/xbmc/network/GUIDialogAccessPoints.h
index f76d8b1bf311c..5ada50280b325 100644
--- a/xbmc/network/GUIDialogAccessPoints.h
+++ b/xbmc/network/GUIDialogAccessPoints.h
@@ -1,8 +1,6 @@
-#ifndef GUI_DIALOG_ACCES_POINTS
-#define GUI_DIALOG_ACCES_POINTS
-
+#pragma once
/*
- * Copyright (C) 2005-2012 Team XBMC
+ * Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -16,8 +14,9 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
*
*/
@@ -25,29 +24,35 @@
#include
#include "guilib/GUIDialog.h"
-#include "Network.h"
+#include "IConnection.h"
+#include "utils/Job.h"
+
+
+const std::string EncodeAccessPointParam(const std::string name, const CIPConfig &ipconfig);
class CFileItemList;
-class CGUIDialogAccessPoints : public CGUIDialog
+class CGUIDialogAccessPoints : public CGUIDialog, public IJobCallback
{
public:
CGUIDialogAccessPoints(void);
virtual ~CGUIDialogAccessPoints(void);
- virtual void OnInitWindow();
virtual bool OnAction(const CAction &action);
- void SetInterfaceName(CStdString interfaceName);
- CStdString GetSelectedAccessPointEssId();
- EncMode GetSelectedAccessPointEncMode();
- bool WasItemSelected();
+ virtual bool OnMessage(CGUIMessage& message);
+ virtual bool OnBack(int actionID);
+ virtual void OnJobComplete(unsigned int jobID, bool success, CJob *job);
private:
- std::vector m_aps;
- CStdString m_interfaceName;
- CStdString m_selectedAPEssId;
- EncMode m_selectedAPEncMode;
- bool m_wasItemSelected;
- CFileItemList *m_accessPoints;
-};
+ void UpdateConnectionList();
+ void DecodeAccessPointParam(const std::string ¶m);
+
+ static const char *ConnectionStateToString(ConnectionState state);
+ static const char *ConnectionTypeToString(ConnectionType type);
+ static const char *EncryptionToString(EncryptionType type);
-#endif
+ std::string m_ipname;
+ CIPConfig m_ipconfig;
+ bool m_use_ipconfig;
+ bool m_doing_connection;
+ CFileItemList *m_connectionsFileList;
+};
diff --git a/xbmc/network/IConnection.h b/xbmc/network/IConnection.h
new file mode 100644
index 0000000000000..fd337e98854c9
--- /dev/null
+++ b/xbmc/network/IConnection.h
@@ -0,0 +1,209 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+#include
+#include
+#include "IPassphraseStorage.h"
+#include
+
+enum ConnectionType
+{
+ NETWORK_CONNECTION_TYPE_UNKNOWN = 0,
+ NETWORK_CONNECTION_TYPE_WIRED,
+ NETWORK_CONNECTION_TYPE_WIFI
+};
+
+enum ConnectionState
+{
+ NETWORK_CONNECTION_STATE_UNKNOWN = 0,
+ NETWORK_CONNECTION_STATE_FAILURE,
+ NETWORK_CONNECTION_STATE_DISCONNECTED,
+ NETWORK_CONNECTION_STATE_CONNECTING,
+ NETWORK_CONNECTION_STATE_CONNECTED
+};
+
+enum EncryptionType
+{
+ NETWORK_CONNECTION_ENCRYPTION_UNKNOWN = 0, // This should be used to flag accesspoints which have some encryption which we cannot connect to.
+ NETWORK_CONNECTION_ENCRYPTION_NONE,
+ NETWORK_CONNECTION_ENCRYPTION_WEP,
+ NETWORK_CONNECTION_ENCRYPTION_WPA,
+ NETWORK_CONNECTION_ENCRYPTION_WPA2,
+ NETWORK_CONNECTION_ENCRYPTION_IEEE8021x
+};
+
+enum IPConfigMethod
+{
+ IP_CONFIG_DHCP,
+ IP_CONFIG_STATIC,
+ IP_CONFIG_DISABLED
+};
+
+class CIPConfig
+{
+public:
+ CIPConfig()
+ {
+ reset();
+ }
+
+ CIPConfig(IPConfigMethod method,
+ const std::string &address, const std::string &netmask,
+ const std::string &gateway, const std::string &nameserver)
+ {
+ m_method = method;
+ m_address = address;
+ m_netmask = netmask;
+ m_gateway = gateway;
+ m_nameserver = nameserver;
+ }
+
+ void reset()
+ {
+ m_method = IP_CONFIG_DISABLED;
+ m_address = "";
+ m_netmask = "";
+ m_gateway = "";
+ m_nameserver = "";
+ }
+
+ IPConfigMethod m_method;
+ std::string m_address;
+ std::string m_netmask;
+ std::string m_gateway;
+ std::string m_nameserver;
+};
+
+class IConnection
+{
+public:
+ virtual ~IConnection() { }
+
+ /*!
+ \brief Get the name of the connection
+
+ \return The name of the connection
+ \sa IConnection
+ */
+ virtual std::string GetName() const = 0;
+
+ /*!
+ \brief Get the IP of the connection
+
+ \return The IP of the connection
+ \sa IConnection
+ */
+ virtual std::string GetAddress() const = 0;
+
+ /*!
+ \brief Get the netmask of the connection
+
+ \return The netmask of the connection
+ \sa IConnection
+ */
+ virtual std::string GetNetmask() const = 0;
+
+ /*!
+ \brief Get the gateway address of the connection
+
+ \return The gateway address of the connection
+ \sa IConnection
+ */
+ virtual std::string GetGateway() const = 0;
+
+ /*!
+ \brief Get the name server of the connection
+
+ \return The name server of the connection
+ \sa IConnection
+ */
+
+ virtual std::string GetNameServer() const = 0;
+
+ /*!
+ \brief Get the mac address of the connection
+
+ \return The mac address of the connection
+ \sa IConnection
+ */
+ virtual std::string GetMacAddress() const = 0;
+
+ /*!
+ \brief Get the connection type
+
+ \return The connection type
+ \sa ConnectionType
+ */
+ virtual ConnectionType GetType() const = 0;
+
+ /*!
+ \brief Get the state of the connection
+
+ \return The state the connection is currently in.
+ \sa ConnectionState
+ */
+ virtual ConnectionState GetState() const = 0;
+
+ /*!
+ \brief Get the speed of the connection
+
+ \return The speed of the connection
+ \sa IConnection
+ */
+ virtual unsigned int GetSpeed() const = 0;
+
+ /*!
+ \brief Get the connection type
+
+ \return The connection method
+ \sa IPConfigMethod
+ */
+ virtual IPConfigMethod GetMethod() const = 0;
+
+ /*!
+ \brief The signal strength of the connection
+
+ \return The signal strength of the connection
+ \sa IConnection
+ */
+ virtual unsigned int GetStrength() const = 0;
+
+ /*!
+ \brief Get the encryption used by the connection
+
+ \return The encryption used by the connection
+ \sa EncryptionType
+ */
+ virtual EncryptionType GetEncryption() const = 0;
+
+ /*!
+ \brief Connect to connection
+
+ \param storage a passphrase provider
+ \param ipconfig a network configuration
+ \returns true if connected, false if not.
+ \sa IPassphraseStorage CIPConfig
+ */
+ virtual bool Connect(IPassphraseStorage *storage, const CIPConfig &ipconfig) = 0;
+};
+
+typedef boost::shared_ptr CConnectionPtr;
+typedef std::vector ConnectionList;
diff --git a/xbmc/network/INetworkManager.h b/xbmc/network/INetworkManager.h
new file mode 100644
index 0000000000000..fafb459e2450d
--- /dev/null
+++ b/xbmc/network/INetworkManager.h
@@ -0,0 +1,68 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IConnection.h"
+
+/*!
+ \ingroup network
+ \brief Callback interface for network events.
+
+ Used by subsystems of the network manager to receive events about the subsystem.
+ It will be called relatively often from application thread to allow thread safe updates
+ of the network states.
+
+ \sa INetworkManager
+ */
+class INetworkEventsCallback
+{
+public:
+ virtual ~INetworkEventsCallback() { }
+
+ virtual void OnConnectionStateChange(ConnectionState state) = 0;
+ virtual void OnConnectionChange(CConnectionPtr connection) = 0;
+ virtual void OnConnectionListChange(ConnectionList list) = 0;
+};
+
+
+/*!
+ \ingroup network
+ \brief Interface for the network subsystems context
+
+ Used by subsystems of the network manager to receive events about the subsystem.
+ It will be called relatively often from application thread to allow thread safe updates
+ of the network states.
+
+ \sa INetworkManager
+ */
+class INetworkManager
+{
+public:
+ virtual ~INetworkManager() { }
+
+ virtual bool CanManageConnections() = 0;
+
+ virtual ConnectionList GetConnections() = 0;
+
+ virtual bool PumpNetworkEvents(INetworkEventsCallback *callback) = 0;
+
+ virtual bool SendWakeOnLan(const char *mac) {return false;};
+};
diff --git a/xbmc/network/IPassphraseStorage.h b/xbmc/network/IPassphraseStorage.h
new file mode 100644
index 0000000000000..894b7ee66a714
--- /dev/null
+++ b/xbmc/network/IPassphraseStorage.h
@@ -0,0 +1,63 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+class IPassphraseStorage
+{
+public:
+ virtual ~IPassphraseStorage() { }
+
+ /*!
+ \brief Invalidate passphrase
+
+ While a connection is connecting it may invalidate any stored passphrase. This is used
+ if the subsystem is not able to store passwords but the connection may have changed passphrase
+
+ \param uuid the unique id of the connection associated with the passphrase
+ \sa IConnection
+ */
+ virtual void InvalidatePassphrase(const std::string &uuid) = 0;
+
+ /*!
+ \brief Get passphrase
+
+ While a connection is connecting it may need to acquire a passphrase. This is used
+ if the subsystem has no stored passphrase.
+
+ \param uuid the unique id of the connection.
+ \param passphrase a string which the passphrase storage will fill in the passphrase.
+ \return true if the passphrase was filled and false if it was some form of failure acquiring it.
+ \sa IConnection
+ */
+ virtual bool GetPassphrase(const std::string &uuid, std::string &passphrase) = 0;
+
+ /*!
+ \brief Store passphrase
+
+ While a connection is connecting it may need to store a passphrase. This is used
+ if the subsystem is not capable of storing the passphrase itself.
+
+ \param uuid the unique id of the connection.
+ \param passphrase is the passphrase to be stored
+ \sa IConnection
+ */
+ virtual void StorePassphrase(const std::string &uuid, const std::string &passphrase) = 0;
+};
diff --git a/xbmc/network/Makefile.in b/xbmc/network/Makefile.in
index e2ffb0bce9454..ecef3a8bec4b6 100644
--- a/xbmc/network/Makefile.in
+++ b/xbmc/network/Makefile.in
@@ -5,13 +5,16 @@ SRCS += EventPacket.cpp
SRCS += EventServer.cpp
SRCS += GUIDialogAccessPoints.cpp
SRCS += GUIDialogNetworkSetup.cpp
-SRCS += Network.cpp
SRCS += Socket.cpp
SRCS += TCPServer.cpp
SRCS += UdpClient.cpp
SRCS += WebServer.cpp
SRCS += ZeroconfBrowser.cpp
SRCS += Zeroconf.cpp
+SRCS += NetworkManager.cpp
+SRCS += NetworkUtils.cpp
+SRCS += NullNetworkManager.cpp
+SRCS += ConnectionJob.cpp
ifeq (@USE_AIRPLAY@, 1)
SRCS += AirPlayServer.cpp
diff --git a/xbmc/network/Network.cpp b/xbmc/network/Network.cpp
deleted file mode 100644
index 9c569582b99d6..0000000000000
--- a/xbmc/network/Network.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2005-2012 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
- *
- */
-
-#include "system.h"
-#include "Network.h"
-#include "Application.h"
-#include "ApplicationMessenger.h"
-#include "libscrobbler/lastfmscrobbler.h"
-#include "libscrobbler/librefmscrobbler.h"
-#include "utils/RssReader.h"
-#include "utils/log.h"
-#include "guilib/LocalizeStrings.h"
-#include "dialogs/GUIDialogKaiToast.h"
-
-#include
-#include
-#include
-
-using namespace std;
-
-/* slightly modified in_ether taken from the etherboot project (http://sourceforge.net/projects/etherboot) */
-bool in_ether (const char *bufp, unsigned char *addr)
-{
- if (strlen(bufp) != 17)
- return false;
-
- char c;
- const char *orig;
- unsigned char *ptr = addr;
- unsigned val;
-
- int i = 0;
- orig = bufp;
-
- while ((*bufp != '\0') && (i < 6))
- {
- val = 0;
- c = *bufp++;
-
- if (isdigit(c))
- val = c - '0';
- else if (c >= 'a' && c <= 'f')
- val = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- val = c - 'A' + 10;
- else
- return false;
-
- val <<= 4;
- c = *bufp;
- if (isdigit(c))
- val |= c - '0';
- else if (c >= 'a' && c <= 'f')
- val |= c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- val |= c - 'A' + 10;
- else if (c == ':' || c == '-' || c == 0)
- val >>= 4;
- else
- return false;
-
- if (c != 0)
- bufp++;
-
- *ptr++ = (unsigned char) (val & 0377);
- i++;
-
- if (*bufp == ':' || *bufp == '-')
- bufp++;
- }
-
- if (bufp - orig != 17)
- return false;
-
- return true;
-}
-
-CNetwork::CNetwork()
-{
- CApplicationMessenger::Get().NetworkMessage(SERVICES_UP, 0);
-}
-
-CNetwork::~CNetwork()
-{
- CApplicationMessenger::Get().NetworkMessage(SERVICES_DOWN, 0);
-}
-
-int CNetwork::ParseHex(char *str, unsigned char *addr)
-{
- int len = 0;
-
- while (*str)
- {
- int tmp;
- if (str[1] == 0)
- return -1;
- if (sscanf(str, "%02x", (unsigned int *)&tmp) != 1)
- return -1;
- addr[len] = tmp;
- len++;
- str += 2;
- }
-
- return len;
-}
-
-CStdString CNetwork::GetHostName(void)
-{
- char hostName[128];
- if (gethostname(hostName, sizeof(hostName)))
- return CStdString("unknown");
- else
- return CStdString(hostName);
-}
-
-
-CNetworkInterface* CNetwork::GetFirstConnectedInterface()
-{
- vector& ifaces = GetInterfaceList();
- vector::const_iterator iter = ifaces.begin();
- while (iter != ifaces.end())
- {
- CNetworkInterface* iface = *iter;
- if (iface && iface->IsConnected())
- return iface;
- ++iter;
- }
-
- return NULL;
-}
-
-bool CNetwork::HasInterfaceForIP(unsigned long address)
-{
- unsigned long subnet;
- unsigned long local;
- vector& ifaces = GetInterfaceList();
- vector::const_iterator iter = ifaces.begin();
- while (iter != ifaces.end())
- {
- CNetworkInterface* iface = *iter;
- if (iface && iface->IsConnected())
- {
- subnet = ntohl(inet_addr(iface->GetCurrentNetmask()));
- local = ntohl(inet_addr(iface->GetCurrentIPAddress()));
- if( (address & subnet) == (local & subnet) )
- return true;
- }
- ++iter;
- }
-
- return false;
-}
-
-bool CNetwork::IsAvailable(bool wait /*= false*/)
-{
- if (wait)
- {
- // NOTE: Not implemented in linuxport branch as 99.9% of the time
- // we have the network setup already. Trunk code has a busy
- // wait for 5 seconds here.
- }
-
- vector& ifaces = GetInterfaceList();
- return (ifaces.size() != 0);
-}
-
-bool CNetwork::IsConnected()
-{
- return GetFirstConnectedInterface() != NULL;
-}
-
-CNetworkInterface* CNetwork::GetInterfaceByName(CStdString& name)
-{
- vector& ifaces = GetInterfaceList();
- vector::const_iterator iter = ifaces.begin();
- while (iter != ifaces.end())
- {
- CNetworkInterface* iface = *iter;
- if (iface && iface->GetName().Equals(name))
- return iface;
- ++iter;
- }
-
- return NULL;
-}
-
-void CNetwork::NetworkMessage(EMESSAGE message, int param)
-{
- switch( message )
- {
- case SERVICES_UP:
- {
- CLog::Log(LOGDEBUG, "%s - Starting network services",__FUNCTION__);
- StartServices();
- }
- break;
- case SERVICES_DOWN:
- {
- CLog::Log(LOGDEBUG, "%s - Signaling network services to stop",__FUNCTION__);
- StopServices(false); //tell network services to stop, but don't wait for them yet
- CLog::Log(LOGDEBUG, "%s - Waiting for network services to stop",__FUNCTION__);
- StopServices(true); //wait for network services to stop
- }
- break;
- }
-}
-
-bool CNetwork::WakeOnLan(const char* mac)
-{
- int i, j, packet;
- unsigned char ethaddr[8];
- unsigned char buf [128];
- unsigned char *ptr;
-
- // Fetch the hardware address
- if (!in_ether(mac, ethaddr))
- {
- CLog::Log(LOGERROR, "%s - Invalid hardware address specified (%s)", __FUNCTION__, mac);
- return false;
- }
-
- // Setup the socket
- if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- {
- CLog::Log(LOGERROR, "%s - Unable to create socket (%s)", __FUNCTION__, strerror (errno));
- return false;
- }
-
- // Set socket options
- struct sockaddr_in saddr;
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
- saddr.sin_port = htons(9);
-
- unsigned int value = 1;
- if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char*) &value, sizeof( unsigned int ) ) == SOCKET_ERROR)
- {
- CLog::Log(LOGERROR, "%s - Unable to set socket options (%s)", __FUNCTION__, strerror (errno));
- closesocket(packet);
- return false;
- }
-
- // Build the magic packet (6 x 0xff + 16 x MAC address)
- ptr = buf;
- for (i = 0; i < 6; i++)
- *ptr++ = 0xff;
-
- for (j = 0; j < 16; j++)
- for (i = 0; i < 6; i++)
- *ptr++ = ethaddr[i];
-
- // Send the magic packet
- if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&saddr, sizeof (saddr)) < 0)
- {
- CLog::Log(LOGERROR, "%s - Unable to send magic packet (%s)", __FUNCTION__, strerror (errno));
- closesocket(packet);
- return false;
- }
-
- closesocket(packet);
- CLog::Log(LOGINFO, "%s - Magic packet send to '%s'", __FUNCTION__, mac);
- return true;
-}
-
-void CNetwork::StartServices()
-{
-#ifdef HAS_TIME_SERVER
- g_application.StartTimeServer();
-#endif
-#ifdef HAS_WEB_SERVER
- if (!g_application.StartWebServer())
- CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33101), g_localizeStrings.Get(33100));
-#endif
-#ifdef HAS_UPNP
- g_application.StartUPnP();
-#endif
-#ifdef HAS_EVENT_SERVER
- if (!g_application.StartEventServer())
- CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33102), g_localizeStrings.Get(33100));
-#endif
-#ifdef HAS_JSONRPC
- if (!g_application.StartJSONRPCServer())
- CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33103), g_localizeStrings.Get(33100));
-#endif
-#ifdef HAS_ZEROCONF
- g_application.StartZeroconf();
-#endif
-#ifdef HAS_AIRPLAY
- g_application.StartAirplayServer();
-#endif
- CLastfmScrobbler::GetInstance()->Init();
- CLibrefmScrobbler::GetInstance()->Init();
- g_rssManager.Start();
-}
-
-void CNetwork::StopServices(bool bWait)
-{
- if (bWait)
- {
-#ifdef HAS_TIME_SERVER
- g_application.StopTimeServer();
-#endif
-#ifdef HAS_UPNP
- g_application.StopUPnP(bWait);
-#endif
-#ifdef HAS_ZEROCONF
- g_application.StopZeroconf();
-#endif
-#ifdef HAS_WEB_SERVER
- g_application.StopWebServer();
-#endif
- CLastfmScrobbler::GetInstance()->Term();
- CLibrefmScrobbler::GetInstance()->Term();
- // smb.Deinit(); if any file is open over samba this will break.
-
- g_rssManager.Stop();
- }
-
-#ifdef HAS_EVENT_SERVER
- g_application.StopEventServer(bWait, false);
-#endif
-#ifdef HAS_JSONRPC
- g_application.StopJSONRPCServer(bWait);
-#endif
-#if defined(HAS_AIRPLAY) || defined(HAS_AIRTUNES)
- g_application.StopAirplayServer(bWait);
-#endif
-}
diff --git a/xbmc/network/Network.h b/xbmc/network/Network.h
deleted file mode 100644
index 1aaa764cea179..0000000000000
--- a/xbmc/network/Network.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#ifndef NETWORK_H_
-#define NETWORK_H_
-
-/*
- * Copyright (C) 2005-2012 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * .
- *
- */
-
-#include
-#include "utils/StdString.h"
-#include "system.h"
-
-enum EncMode { ENC_NONE = 0, ENC_WEP = 1, ENC_WPA = 2, ENC_WPA2 = 3 };
-enum NetworkAssignment { NETWORK_DASH = 0, NETWORK_DHCP = 1, NETWORK_STATIC = 2, NETWORK_DISABLED = 3 };
-
-class NetworkAccessPoint
-{
-public:
- NetworkAccessPoint(CStdString& essId, int quality, EncMode encryption)
- {
- m_essId = essId;
- m_quality = quality;
- m_encryptionMode = encryption;
- }
-
- CStdString getEssId() { return m_essId; }
- int getQuality() { return m_quality; }
- EncMode getEncryptionMode() { return m_encryptionMode; }
-
-private:
- CStdString m_essId;
- int m_quality;
- EncMode m_encryptionMode;
-};
-
-class CNetworkInterface
-{
-public:
- virtual ~CNetworkInterface() {};
-
- virtual CStdString& GetName(void) = 0;
-
- virtual bool IsEnabled(void) = 0;
- virtual bool IsConnected(void) = 0;
- virtual bool IsWireless(void) = 0;
-
- virtual CStdString GetMacAddress(void) = 0;
- virtual void GetMacAddressRaw(char rawMac[6]) = 0;
-
- virtual CStdString GetCurrentIPAddress() = 0;
- virtual CStdString GetCurrentNetmask() = 0;
- virtual CStdString GetCurrentDefaultGateway(void) = 0;
- virtual CStdString GetCurrentWirelessEssId(void) = 0;
-
- // Returns the list of access points in the area
- virtual std::vector GetAccessPoints(void) = 0;
-
- virtual void GetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode) = 0;
- virtual void SetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode) = 0;
-};
-
-
-
-class CNetwork
-{
-public:
- enum EMESSAGE
- {
- SERVICES_UP,
- SERVICES_DOWN
- };
-
- CNetwork();
- virtual ~CNetwork();
-
- // Return our hostname
- virtual CStdString GetHostName(void);
-
- // Return the list of interfaces
- virtual std::vector& GetInterfaceList(void) = 0;
- CNetworkInterface* GetInterfaceByName(CStdString& name);
-
- // Return the first interface which is active
- virtual CNetworkInterface* GetFirstConnectedInterface(void);
-
- // Return true if there is a interface for the same network as address
- bool HasInterfaceForIP(unsigned long address);
-
- // Return true if there's at least one defined network interface
- bool IsAvailable(bool wait = false);
-
- // Return true if there's at least one interface which is connected
- bool IsConnected(void);
-
- // Return true if the magic packet was send
- bool WakeOnLan(const char *mac);
-
- // Get/set the nameserver(s)
- virtual std::vector GetNameServers(void) = 0;
- virtual void SetNameServers(std::vector nameServers) = 0;
-
- // callback from application controlled thread to handle any setup
- void NetworkMessage(EMESSAGE message, int param);
-
- void StartServices();
- void StopServices(bool bWait);
-
- static int ParseHex(char *str, unsigned char *addr);
-};
-#ifdef HAS_LINUX_NETWORK
-#include "linux/NetworkLinux.h"
-#else
-#include "windows/NetworkWin32.h"
-#endif
-#endif
diff --git a/xbmc/network/NetworkManager.cpp b/xbmc/network/NetworkManager.cpp
new file mode 100644
index 0000000000000..275692cb6ebe3
--- /dev/null
+++ b/xbmc/network/NetworkManager.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "NetworkManager.h"
+#include "NullNetworkManager.h"
+#include "Application.h"
+#include "ApplicationMessenger.h"
+#include "dialogs/GUIDialogKaiToast.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/GUIWindowManager.h"
+#include "libscrobbler/lastfmscrobbler.h"
+#include "libscrobbler/librefmscrobbler.h"
+#include "linux/ConnmanNetworkManager.h"
+#include "linux/PosixNetworkManager.h"
+#include "windows/WinNetworkManager.h"
+#include "utils/log.h"
+#include "utils/RssReader.h"
+
+//-----------------------------------------------------------------------
+//-----------------------------------------------------------------------
+CNetworkManager::CNetworkManager()
+{
+ m_timer = NULL;
+ m_instance = NULL;
+ m_state = NETWORK_CONNECTION_STATE_UNKNOWN;
+}
+
+CNetworkManager::~CNetworkManager()
+{
+ delete m_instance;
+}
+
+void CNetworkManager::Initialize()
+{
+#ifdef HAS_DBUS
+// if (CConnmanNetworkManager::HasConnman())
+// m_instance = new CConnmanNetworkManager();
+#endif
+
+#if defined(TARGET_POSIX)
+ if (m_instance == NULL)
+ m_instance = new CPosixNetworkManager();
+#endif
+
+#ifdef TARGET_WINDOWS
+ if (m_instance == NULL)
+ m_instance = new CWinNetworkManager();
+#endif
+
+ if (m_instance == NULL)
+ m_instance = new CNullNetworkManager();
+
+ m_defaultConnection = CConnectionPtr(new CNullConnection());
+ OnConnectionListChange(m_instance->GetConnections());
+}
+
+bool CNetworkManager::PumpNetworkEvents()
+{
+#if defined(TARGET_ANDROID)
+ if (!g_application.m_pPlayer)
+ {
+ if (!m_timer && !IsConnected())
+ {
+ CLog::Log(LOGDEBUG, "NetworkManager: not connected, bgn timout");
+ m_timer = new CStopWatch();
+ m_timer->StartZero();
+ }
+ }
+ if (m_timer && m_timer->GetElapsedSeconds() > 15)
+ {
+ CLog::Log(LOGDEBUG, "NetworkManager: not connected, end timout");
+ OnConnectionListChange(m_instance->GetConnections());
+ delete m_timer, m_timer = NULL;
+ }
+#endif
+
+ return m_instance->PumpNetworkEvents(this);
+}
+
+std::string CNetworkManager::GetDefaultConnectionName()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetName();
+ else
+ return std::string("opps");
+}
+
+std::string CNetworkManager::GetDefaultConnectionAddress()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetAddress();
+ else
+ return std::string("opps");
+}
+
+std::string CNetworkManager::GetDefaultConnectionNetmask()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetNetmask();
+ else
+ return std::string("opps");
+}
+
+std::string CNetworkManager::GetDefaultConnectionMacAddress()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetMacAddress();
+ else
+ return std::string("opps");
+}
+
+std::string CNetworkManager::GetDefaultConnectionGateway()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetGateway();
+ else
+ return std::string("opps");
+}
+
+std::string CNetworkManager::GetDefaultConnectionNameServer()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetNameServer();
+ else
+ return std::string("127.0.0.1");
+}
+
+ConnectionType CNetworkManager::GetDefaultConnectionType()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetType();
+ else
+ return NETWORK_CONNECTION_TYPE_UNKNOWN;
+}
+
+IPConfigMethod CNetworkManager::GetDefaultConnectionMethod()
+{
+ if (m_defaultConnection)
+ return m_defaultConnection->GetMethod();
+ else
+ return IP_CONFIG_DISABLED;
+}
+
+ConnectionState CNetworkManager::GetDefaultConnectionState()
+{
+ return m_state;
+}
+
+bool CNetworkManager::IsConnected()
+{
+ return GetDefaultConnectionState() == NETWORK_CONNECTION_STATE_CONNECTED;
+}
+
+bool CNetworkManager::IsAvailable(bool wait)
+{
+ return true;
+}
+
+bool CNetworkManager::CanManageConnections()
+{
+ return m_instance->CanManageConnections();
+}
+
+ConnectionList CNetworkManager::GetConnections()
+{
+ return m_connections;
+}
+
+void CNetworkManager::OnConnectionStateChange(ConnectionState state)
+{
+ ConnectionState oldState = m_state;
+ m_state = state;
+
+ if (m_state != oldState)
+ CLog::Log(LOGDEBUG, "NetworkManager: State changed to %s", ConnectionStateToString(m_state));
+
+ if (oldState != NETWORK_CONNECTION_STATE_CONNECTED && m_state == NETWORK_CONNECTION_STATE_CONNECTED)
+ StartServices();
+ else if (oldState == NETWORK_CONNECTION_STATE_CONNECTED && oldState != m_state)
+ StopServices();
+}
+
+void CNetworkManager::OnConnectionChange(CConnectionPtr connection)
+{
+ if (connection->GetState() == NETWORK_CONNECTION_STATE_CONNECTED)
+ m_defaultConnection = connection;
+
+ if (g_windowManager.GetWindow(WINDOW_DIALOG_ACCESS_POINTS))
+ {
+ CAction action(ACTION_CONNECTIONS_REFRESH);
+ CApplicationMessenger::Get().SendAction(action, WINDOW_DIALOG_ACCESS_POINTS);
+ }
+}
+
+void CNetworkManager::OnConnectionListChange(ConnectionList list)
+{
+ m_connections = list;
+
+ for (unsigned int i = 0; i < m_connections.size(); i++)
+ {
+ if (m_connections[i]->GetState() == NETWORK_CONNECTION_STATE_CONNECTED)
+ {
+ m_defaultConnection = m_connections[i];
+ OnConnectionStateChange(NETWORK_CONNECTION_STATE_CONNECTED);
+ break;
+ }
+ }
+
+ if (g_windowManager.GetWindow(WINDOW_DIALOG_ACCESS_POINTS))
+ {
+ CAction action(ACTION_CONNECTIONS_REFRESH);
+ CApplicationMessenger::Get().SendAction(action, WINDOW_DIALOG_ACCESS_POINTS);
+ }
+}
+
+void CNetworkManager::NetworkMessage(EMESSAGE message, int param)
+{
+ switch( message )
+ {
+ case SERVICES_UP:
+ {
+ CLog::Log(LOGDEBUG, "%s - Starting network services",__FUNCTION__);
+ StartServices();
+ }
+ break;
+ case SERVICES_DOWN:
+ {
+ CLog::Log(LOGDEBUG, "%s - Signaling network services to stop",__FUNCTION__);
+ StopServices(false); //tell network services to stop, but don't wait for them yet
+ CLog::Log(LOGDEBUG, "%s - Waiting for network services to stop",__FUNCTION__);
+ StopServices(true); //wait for network services to stop
+ }
+ break;
+ }
+}
+
+bool CNetworkManager::WakeOnLan(const char *mac)
+{
+ return m_instance->SendWakeOnLan(mac);
+}
+
+void CNetworkManager::StartServices()
+{
+ CLog::Log(LOGDEBUG, "NetworkManager: Starting network services");
+
+ // TODO: fix properly
+ system("/etc/init.d/S49ntp restart");
+
+#ifdef HAS_TIME_SERVER
+ g_application.StartTimeServer();
+#endif
+#ifdef HAS_WEB_SERVER
+ if (!g_application.StartWebServer())
+ CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33101), g_localizeStrings.Get(33100));
+#endif
+#ifdef HAS_UPNP
+ g_application.StartUPnP();
+#endif
+#ifdef HAS_EVENT_SERVER
+ if (!g_application.StartEventServer())
+ CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33102), g_localizeStrings.Get(33100));
+#endif
+#ifdef HAS_DBUS_SERVER
+ g_application.StartDbusServer();
+#endif
+#ifdef HAS_JSONRPC
+ if (!g_application.StartJSONRPCServer())
+ CGUIDialogKaiToast::QueueNotification("DefaultIconWarning.png", g_localizeStrings.Get(33103), g_localizeStrings.Get(33100));
+#endif
+#ifdef HAS_ZEROCONF
+ g_application.StartZeroconf();
+#endif
+#ifdef HAS_AIRPLAY
+ g_application.StartAirplayServer();
+#endif
+ CLastfmScrobbler::GetInstance()->Init();
+ CLibrefmScrobbler::GetInstance()->Init();
+ g_rssManager.Start();
+}
+
+void CNetworkManager::StopServices()
+{
+ CLog::Log(LOGDEBUG, "NetworkManager: Stopping network services");
+ StopServices(false);
+ CLog::Log(LOGDEBUG, "NetworkManager: Waiting for network services to stop");
+ StopServices(true);
+}
+
+void CNetworkManager::StopServices(bool wait)
+{
+ if (wait)
+ {
+#ifdef HAS_TIME_SERVER
+ g_application.StopTimeServer();
+#endif
+#ifdef HAS_UPNP
+ g_application.StopUPnP(wait);
+#endif
+#ifdef HAS_ZEROCONF
+ g_application.StopZeroconf();
+#endif
+#ifdef HAS_WEB_SERVER
+ g_application.StopWebServer();
+#endif
+ CLastfmScrobbler::GetInstance()->Term();
+ CLibrefmScrobbler::GetInstance()->Term();
+ // smb.Deinit(); if any file is open over samba this will break.
+
+ g_rssManager.Stop();
+ }
+
+#ifdef HAS_EVENT_SERVER
+ g_application.StopEventServer(wait, false);
+#endif
+#ifdef HAS_DBUS_SERVER
+ g_application.StopDbusServer(wait);
+#endif
+#ifdef HAS_JSONRPC
+ g_application.StopJSONRPCServer(wait);
+#endif
+#if defined(HAS_AIRPLAY) || defined(HAS_AIRTUNES)
+ g_application.StopAirplayServer(wait);
+#endif
+}
+
+const char *CNetworkManager::ConnectionStateToString(ConnectionState state)
+{
+ switch (state)
+ {
+ case NETWORK_CONNECTION_STATE_FAILURE:
+ return "failure";
+ case NETWORK_CONNECTION_STATE_DISCONNECTED:
+ return "disconnect";
+ case NETWORK_CONNECTION_STATE_CONNECTING:
+ return "connecting";
+ case NETWORK_CONNECTION_STATE_CONNECTED:
+ return "connected";
+ case NETWORK_CONNECTION_STATE_UNKNOWN:
+ default:
+ return "unknown";
+ }
+}
diff --git a/xbmc/network/NetworkManager.h b/xbmc/network/NetworkManager.h
new file mode 100644
index 0000000000000..010eb6034e89d
--- /dev/null
+++ b/xbmc/network/NetworkManager.h
@@ -0,0 +1,83 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "INetworkManager.h"
+
+class CStopWatch;
+
+class CNetworkManager : public INetworkEventsCallback
+{
+public:
+ enum EMESSAGE
+ {
+ SERVICES_UP,
+ SERVICES_DOWN
+ };
+
+ CNetworkManager();
+ virtual ~CNetworkManager();
+
+ void Initialize();
+
+ bool PumpNetworkEvents();
+
+ std::string GetDefaultConnectionName();
+ std::string GetDefaultConnectionAddress();
+ std::string GetDefaultConnectionNetmask();
+ std::string GetDefaultConnectionGateway();
+ std::string GetDefaultConnectionNameServer();
+ std::string GetDefaultConnectionMacAddress();
+
+ ConnectionType GetDefaultConnectionType();
+ ConnectionState GetDefaultConnectionState();
+ IPConfigMethod GetDefaultConnectionMethod();
+
+ bool IsConnected();
+
+ bool IsAvailable(bool wait = false);
+
+ bool CanManageConnections();
+
+ ConnectionList GetConnections();
+
+ virtual void OnConnectionStateChange(ConnectionState state);
+ virtual void OnConnectionChange(CConnectionPtr connection);
+ virtual void OnConnectionListChange(ConnectionList list);
+
+ // Return true if the magic packet was send
+ bool WakeOnLan(const char *mac);
+
+ // callback from application controlled thread to handle any setup
+ void NetworkMessage(EMESSAGE message, int param);
+
+ void StartServices();
+ void StopServices();
+private:
+ void StopServices(bool wait);
+ const char* ConnectionStateToString(ConnectionState state);
+
+ INetworkManager *m_instance;
+ CConnectionPtr m_defaultConnection;
+ ConnectionList m_connections;
+ ConnectionState m_state;
+ CStopWatch *m_timer;
+};
diff --git a/xbmc/network/NetworkUtils.cpp b/xbmc/network/NetworkUtils.cpp
new file mode 100644
index 0000000000000..810533d41ae28
--- /dev/null
+++ b/xbmc/network/NetworkUtils.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "NetworkUtils.h"
+#include
+#include
+
+std::string CNetworkUtils::IPTotring(unsigned int ip)
+{
+ char buffer[16];
+ sprintf(buffer, "%i:%i:%i:%i", ip & 0xff, (ip & (0xff << 8)) >> 8, (ip & (0xff << 16)) >> 16, (ip & (0xff << 24)) >> 24);
+ std::string returnString = buffer;
+ return returnString;
+}
+
+// slightly modified in_ether taken from the etherboot project (http://sourceforge.net/projects/etherboot)
+bool CNetworkUtils::in_ether(const char *bufp, unsigned char *addr)
+{
+ if (strlen(bufp) != 17)
+ return false;
+
+ char c;
+ const char *orig;
+ unsigned char *ptr = addr;
+ unsigned val;
+
+ int i = 0;
+ orig = bufp;
+
+ while ((*bufp != '\0') && (i < 6))
+ {
+ val = 0;
+ c = *bufp++;
+
+ if (isdigit(c))
+ val = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ val = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ val = c - 'A' + 10;
+ else
+ return false;
+
+ val <<= 4;
+ c = *bufp;
+ if (isdigit(c))
+ val |= c - '0';
+ else if (c >= 'a' && c <= 'f')
+ val |= c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ val |= c - 'A' + 10;
+ else if (c == ':' || c == '-' || c == 0)
+ val >>= 4;
+ else
+ return false;
+
+ if (c != 0)
+ bufp++;
+
+ *ptr++ = (unsigned char) (val & 0377);
+ i++;
+
+ if (*bufp == ':' || *bufp == '-')
+ bufp++;
+ }
+
+ if (bufp - orig != 17)
+ return false;
+
+ return true;
+}
diff --git a/xbmc/network/NetworkUtils.h b/xbmc/network/NetworkUtils.h
new file mode 100644
index 0000000000000..bad4f4eafdd62
--- /dev/null
+++ b/xbmc/network/NetworkUtils.h
@@ -0,0 +1,31 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include
+
+class CNetworkUtils
+{
+public:
+ static std::string IPTotring(unsigned int ip);
+ static bool in_ether(const char *bufp, unsigned char *addr);
+
+};
diff --git a/xbmc/network/NullNetworkManager.cpp b/xbmc/network/NullNetworkManager.cpp
new file mode 100644
index 0000000000000..98c84b33671f1
--- /dev/null
+++ b/xbmc/network/NullNetworkManager.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "NullNetworkManager.h"
+
+//-----------------------------------------------------------------------
+//-----------------------------------------------------------------------
+CNullConnection::~CNullConnection()
+{
+}
+
+std::string CNullConnection::GetName() const
+{
+ return "no connection";
+}
+
+std::string CNullConnection::GetAddress() const
+{
+ return "127.0.0.1";
+}
+
+std::string CNullConnection::GetNetmask() const
+{
+ return "255.255.255.0";
+}
+
+std::string CNullConnection::GetGateway() const
+{
+ return "127.0.0.1";
+}
+
+std::string CNullConnection::GetNameServer() const
+{
+ return "127.0.0.1";
+}
+
+std::string CNullConnection::GetMacAddress() const
+{
+ return "00:00:00:00:00:00";
+}
+
+ConnectionType CNullConnection::GetType() const
+{
+ return NETWORK_CONNECTION_TYPE_UNKNOWN;
+}
+
+unsigned int CNullConnection::GetSpeed() const
+{
+ return 100;
+}
+
+ConnectionState CNullConnection::GetState() const
+{
+ return NETWORK_CONNECTION_STATE_DISCONNECTED;
+}
+
+IPConfigMethod CNullConnection::GetMethod() const
+{
+ return IP_CONFIG_DISABLED;
+}
+
+unsigned int CNullConnection::GetStrength() const
+{
+ return 100;
+}
+
+EncryptionType CNullConnection::GetEncryption() const
+{
+ return NETWORK_CONNECTION_ENCRYPTION_NONE;
+}
+
+bool CNullConnection::Connect(IPassphraseStorage *storage, const CIPConfig &ipconfig)
+{
+ return false;
+}
+
+
+//-----------------------------------------------------------------------
+//-----------------------------------------------------------------------
+CNullNetworkManager::~CNullNetworkManager()
+{
+}
+
+bool CNullNetworkManager::CanManageConnections()
+{
+ return false;
+}
+
+ConnectionList CNullNetworkManager::GetConnections()
+{
+ ConnectionList list;
+ list.push_back(CConnectionPtr(new CNullConnection()));
+ return list;
+}
+
+bool CNullNetworkManager::PumpNetworkEvents(INetworkEventsCallback *callback)
+{
+ return true;
+}
diff --git a/xbmc/network/NullNetworkManager.h b/xbmc/network/NullNetworkManager.h
new file mode 100644
index 0000000000000..7268bd4e1da92
--- /dev/null
+++ b/xbmc/network/NullNetworkManager.h
@@ -0,0 +1,55 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "INetworkManager.h"
+
+class CNullConnection : public IConnection
+{
+public:
+ virtual ~CNullConnection();
+
+ virtual std::string GetName() const;
+ virtual std::string GetAddress() const;
+ virtual std::string GetNetmask() const;
+ virtual std::string GetGateway() const;
+ virtual std::string GetNameServer() const;
+ virtual std::string GetMacAddress() const;
+
+ virtual ConnectionType GetType() const;
+ virtual ConnectionState GetState() const;
+ virtual unsigned int GetSpeed() const;
+ virtual IPConfigMethod GetMethod() const;
+ virtual unsigned int GetStrength() const;
+ virtual EncryptionType GetEncryption() const;
+
+ virtual bool Connect(IPassphraseStorage *storage, const CIPConfig &ipconfig);
+};
+
+class CNullNetworkManager : public INetworkManager
+{
+ virtual ~CNullNetworkManager();
+
+ virtual bool CanManageConnections();
+
+ virtual ConnectionList GetConnections();
+ virtual bool PumpNetworkEvents(INetworkEventsCallback *callback);
+};
diff --git a/xbmc/network/UdpClient.cpp b/xbmc/network/UdpClient.cpp
index 8fad6579df6e5..0aa581d61aea9 100644
--- a/xbmc/network/UdpClient.cpp
+++ b/xbmc/network/UdpClient.cpp
@@ -23,7 +23,6 @@
#ifdef _LINUX
#include
#endif
-#include "Network.h"
#include "guilib/GraphicContext.h"
#include "utils/log.h"
#include "utils/TimeUtils.h"
diff --git a/xbmc/network/Zeroconf.cpp b/xbmc/network/Zeroconf.cpp
index e83eced22ac4e..ec69f70a3a14c 100644
--- a/xbmc/network/Zeroconf.cpp
+++ b/xbmc/network/Zeroconf.cpp
@@ -43,7 +43,7 @@
//should be optimized away
class CZeroconfDummy : public CZeroconf
{
- virtual bool doPublishService(const std::string&, const std::string&, const std::string&, unsigned int, std::map)
+ virtual bool doPublishService(const std::string&, const std::string&, const std::string&, unsigned int, const std::vector >&)
{
return false;
}
@@ -68,7 +68,7 @@ bool CZeroconf::PublishService(const std::string& fcr_identifier,
const std::string& fcr_type,
const std::string& fcr_name,
unsigned int f_port,
- std::map txt)
+ const std::vector >& txt)
{
CSingleLock lock(*mp_crit_sec);
CZeroconf::PublishInfo info = {fcr_type, fcr_name, f_port, txt};
diff --git a/xbmc/network/Zeroconf.h b/xbmc/network/Zeroconf.h
index 52075a5b07ee6..377f817d0f4f3 100644
--- a/xbmc/network/Zeroconf.h
+++ b/xbmc/network/Zeroconf.h
@@ -22,6 +22,7 @@
#include
#include