aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/skin.confluence/720p/Home.xml4
-rwxr-xr-xlanguage/English/strings.po7
-rw-r--r--lib/ffmpeg/libavcodec/dxva2.h1
-rw-r--r--lib/ffmpeg/libavcodec/dxva2_mpeg2.c25
-rw-r--r--lib/ffmpeg/patches/0018-dxva-mpeg2-Allocate-slices-array-dynamically-fixes-v.patch75
-rw-r--r--lib/ffmpeg/patches/0019-dxva-mpeg2-speed-up-slice-allocation.patch75
-rw-r--r--lib/ffmpeg/patches/0062-backport-dxva2-bump-max-number-of-slices.patch28
-rw-r--r--project/Win32BuildSetup/buildpvraddons.bat2
-rw-r--r--tools/depends/target/xbmc-pvr-addons/Makefile2
-rw-r--r--xbmc/addons/Addon.cpp3
-rw-r--r--xbmc/addons/AddonDatabase.cpp158
-rw-r--r--xbmc/addons/AddonDatabase.h32
-rw-r--r--xbmc/addons/AddonInstaller.cpp17
-rw-r--r--xbmc/addons/AddonInstaller.h8
-rw-r--r--xbmc/addons/AddonVersion.cpp5
-rw-r--r--xbmc/addons/AddonVersion.h1
-rw-r--r--xbmc/addons/Repository.cpp16
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp10
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp2
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp5
-rw-r--r--xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp19
-rw-r--r--xbmc/cores/dvdplayer/DVDPlayer.cpp14
-rw-r--r--xbmc/cores/omxplayer/OMXAudio.cpp6
-rw-r--r--xbmc/cores/omxplayer/OMXPlayer.cpp13
-rw-r--r--xbmc/cores/paplayer/CodecFactory.cpp2
-rw-r--r--xbmc/cores/paplayer/FLACcodec.cpp5
-rw-r--r--xbmc/cores/paplayer/PAPlayer.cpp23
-rw-r--r--xbmc/dbwrappers/Database.cpp29
-rw-r--r--xbmc/dbwrappers/Database.h26
-rw-r--r--xbmc/dbwrappers/mysqldataset.cpp7
-rw-r--r--xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp2
-rw-r--r--xbmc/guilib/GUIButtonControl.cpp2
-rw-r--r--xbmc/music/MusicDatabase.cpp11
-rw-r--r--xbmc/network/upnp/UPnPInternal.cpp16
-rw-r--r--xbmc/network/upnp/UPnPInternal.h11
-rw-r--r--xbmc/network/upnp/UPnPPlayer.cpp17
-rw-r--r--xbmc/network/upnp/UPnPRenderer.cpp1
-rw-r--r--xbmc/playlists/PlayListM3U.cpp5
-rw-r--r--xbmc/pvr/PVRManager.cpp6
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.cpp13
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.h13
-rw-r--r--xbmc/settings/AdvancedSettings.cpp2
-rw-r--r--xbmc/video/dialogs/GUIDialogSubtitles.cpp5
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoInfo.cpp13
-rw-r--r--xbmc/video/windows/GUIWindowFullScreen.cpp42
-rw-r--r--xbmc/video/windows/GUIWindowVideoNav.cpp3
46 files changed, 424 insertions, 358 deletions
diff --git a/addons/skin.confluence/720p/Home.xml b/addons/skin.confluence/720p/Home.xml
index 8572e35d09..f4aaf56dba 100644
--- a/addons/skin.confluence/720p/Home.xml
+++ b/addons/skin.confluence/720p/Home.xml
@@ -967,14 +967,14 @@
<left>0</left>
<top>6</top>
<width>128</width>
- <height>50</height>
+ <height>63</height>
<texture>SideFade.png</texture>
</control>
<control type="image">
<left>128r</left>
<top>6</top>
<width>128</width>
- <height>60</height>
+ <height>63</height>
<texture flipx="true">SideFade.png</texture>
</control>
</control>
diff --git a/language/English/strings.po b/language/English/strings.po
index e6c9a8933b..37ac8d79ce 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -9846,7 +9846,12 @@ msgctxt "#20321"
msgid "Scanning albums using %s"
msgstr ""
-#empty strings from id 20322 to 20323
+#empty string with id 20322
+
+#: xbmc/video/windows/GUIWindowVideoNav.cpp
+msgctxt "#20323"
+msgid "Movie plot"
+msgstr ""
msgctxt "#20324"
msgid "Play part..."
diff --git a/lib/ffmpeg/libavcodec/dxva2.h b/lib/ffmpeg/libavcodec/dxva2.h
index 881b48dac5..ac39e06917 100644
--- a/lib/ffmpeg/libavcodec/dxva2.h
+++ b/lib/ffmpeg/libavcodec/dxva2.h
@@ -86,7 +86,6 @@ struct dxva_context {
* Private to the FFmpeg AVHWAccel implementation
*/
unsigned report_id;
- unsigned last_slice_count;
};
/**
diff --git a/lib/ffmpeg/libavcodec/dxva2_mpeg2.c b/lib/ffmpeg/libavcodec/dxva2_mpeg2.c
index e967770208..5db7316876 100644
--- a/lib/ffmpeg/libavcodec/dxva2_mpeg2.c
+++ b/lib/ffmpeg/libavcodec/dxva2_mpeg2.c
@@ -22,13 +22,12 @@
#include "dxva2_internal.h"
+#define MAX_SLICES 1024
struct dxva2_picture_context {
DXVA_PictureParameters pp;
DXVA_QmatrixData qm;
unsigned slice_count;
- DXVA_SliceInfo *slice;
- unsigned int slice_alloc;
-
+ DXVA_SliceInfo slice[MAX_SLICES];
const uint8_t *bitstream;
unsigned bitstream_size;
};
@@ -220,20 +219,9 @@ static int dxva2_mpeg2_start_frame(AVCodecContext *avctx,
fill_quantization_matrices(avctx, ctx, s, &ctx_pic->qm);
ctx_pic->slice_count = 0;
- ctx_pic->slice = NULL;
- ctx_pic->slice_alloc = 0;
ctx_pic->bitstream_size = 0;
ctx_pic->bitstream = NULL;
- if (ctx->last_slice_count > 0)
- {
- ctx_pic->slice = av_fast_realloc(NULL,
- &ctx_pic->slice_alloc,
- ctx->last_slice_count * sizeof(DXVA_SliceInfo));
- if (!ctx_pic->slice)
- return -1;
- }
-
return 0;
}
@@ -244,14 +232,9 @@ static int dxva2_mpeg2_decode_slice(AVCodecContext *avctx,
struct dxva2_picture_context *ctx_pic =
s->current_picture_ptr->f.hwaccel_picture_private;
unsigned position;
- DXVA_SliceInfo* slice;
- slice = av_fast_realloc(ctx_pic->slice,
- &ctx_pic->slice_alloc,
- (ctx_pic->slice_count + 1) * sizeof(DXVA_SliceInfo));
- if (!slice)
+ if (ctx_pic->slice_count >= MAX_SLICES)
return -1;
- ctx_pic->slice = slice;
if (!ctx_pic->bitstream)
ctx_pic->bitstream = buffer;
@@ -268,7 +251,6 @@ static int dxva2_mpeg2_end_frame(AVCodecContext *avctx)
struct MpegEncContext *s = avctx->priv_data;
struct dxva2_picture_context *ctx_pic =
s->current_picture_ptr->f.hwaccel_picture_private;
- struct dxva_context *ctx = avctx->hwaccel_context;
int ret;
if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
@@ -280,7 +262,6 @@ static int dxva2_mpeg2_end_frame(AVCodecContext *avctx)
if (!ret)
ff_mpeg_draw_horiz_band(s, 0, avctx->height);
- ctx->last_slice_count = ctx_pic->slice_count;
return ret;
}
diff --git a/lib/ffmpeg/patches/0018-dxva-mpeg2-Allocate-slices-array-dynamically-fixes-v.patch b/lib/ffmpeg/patches/0018-dxva-mpeg2-Allocate-slices-array-dynamically-fixes-v.patch
deleted file mode 100644
index 87e31c5b70..0000000000
--- a/lib/ffmpeg/patches/0018-dxva-mpeg2-Allocate-slices-array-dynamically-fixes-v.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 40f4c15370f7027dc5422edcb10e8a3b7e58e83d Mon Sep 17 00:00:00 2001
-From: CrystalP <CrystalP@xbmc.org>
-Date: Wed, 5 Oct 2011 12:38:30 -0400
-Subject: [PATCH 18/24] dxva-mpeg2 Allocate slices array dynamically - fixes
- videos with > 175 slices. They used to result in
- images with a black bottom.
-
-sample on team ftp samples/PR471/too_many_slices.ts
-
-Inspired by the vaapi code to reallocate the slices array for each new slice.
-Could be more efficient if the array could be preserved for all frames and
-freed only at the end of the video, but there doesn't seem to be anywhere
-appropriate to free the memory at the end.
-
-Alternative is to allocate the proper size straight away for a new frame,
-instead of realloc'ing for each slice.
----
- libavcodec/dxva2_mpeg2.c | 14 +++++++++++---
- 1 file changed, 11 insertions(+), 3 deletions(-)
-
-diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
-index 951305d..8ba83b6 100644
---- a/libavcodec/dxva2_mpeg2.c
-+++ b/libavcodec/dxva2_mpeg2.c
-@@ -22,12 +22,12 @@
-
- #include "dxva2_internal.h"
-
--#define MAX_SLICES (SLICE_MAX_START_CODE - SLICE_MIN_START_CODE + 1)
- struct dxva2_picture_context {
- DXVA_PictureParameters pp;
- DXVA_QmatrixData qm;
- unsigned slice_count;
-- DXVA_SliceInfo slice[MAX_SLICES];
-+ DXVA_SliceInfo *slice;
-+ unsigned int slice_alloc;
-
- const uint8_t *bitstream;
- unsigned bitstream_size;
-@@ -220,6 +220,8 @@ static int start_frame(AVCodecContext *avctx,
- fill_quantization_matrices(avctx, ctx, s, &ctx_pic->qm);
-
- ctx_pic->slice_count = 0;
-+ ctx_pic->slice = NULL;
-+ ctx_pic->slice_alloc = 0;
- ctx_pic->bitstream_size = 0;
- ctx_pic->bitstream = NULL;
- return 0;
-@@ -232,9 +234,14 @@ static int decode_slice(AVCodecContext *avctx,
- struct dxva2_picture_context *ctx_pic =
- s->current_picture_ptr->f.hwaccel_picture_private;
- unsigned position;
-+ DXVA_SliceInfo* slice;
-
-- if (ctx_pic->slice_count >= MAX_SLICES)
-+ slice = av_fast_realloc(ctx_pic->slice,
-+ &ctx_pic->slice_alloc,
-+ (ctx_pic->slice_count + 1) * sizeof(DXVA_SliceInfo));
-+ if (!slice)
- return -1;
-+ ctx_pic->slice = slice;
-
- if (!ctx_pic->bitstream)
- ctx_pic->bitstream = buffer;
-@@ -258,6 +265,7 @@ static int end_frame(AVCodecContext *avctx)
- &ctx_pic->pp, sizeof(ctx_pic->pp),
- &ctx_pic->qm, sizeof(ctx_pic->qm),
- commit_bitstream_and_slice_buffer);
-+ av_freep(ctx_pic->slice);
- }
-
- AVHWAccel ff_mpeg2_dxva2_hwaccel = {
---
-1.7.9.4
-
diff --git a/lib/ffmpeg/patches/0019-dxva-mpeg2-speed-up-slice-allocation.patch b/lib/ffmpeg/patches/0019-dxva-mpeg2-speed-up-slice-allocation.patch
deleted file mode 100644
index 4336c3180f..0000000000
--- a/lib/ffmpeg/patches/0019-dxva-mpeg2-speed-up-slice-allocation.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 681f74b224e16a4df7f8c4e31a9be56975d57e10 Mon Sep 17 00:00:00 2001
-From: CrystalP <CrystalP@xbmc.org>
-Date: Mon, 10 Oct 2011 19:42:50 -0400
-Subject: [PATCH 19/24] dxva-mpeg2 speed up slice allocation
-
-The number of slices is not very likely to change from frame to frame, so
-at the beginning of a new frame, allocate memory for the amount of slices of
-the previous frame. Saves a lot of reallocation, for some TV capture samples
-there are over 200 slices.
-
-There wasn't anywhere really appropriate to store last_slice_count (needs to
-live from first frame to last frame), so this is likely to cause discussion to
-merge upstream.
-Adding members to dxva_context breaks ABI, which we don't care too much about
-since on Windows we don't support external ffmpeg.
-dxva mpeg2 code also has access to MpegEncContext, but adding there would
-likely break ABI as well.
----
- libavcodec/dxva2.h | 1 +
- libavcodec/dxva2_mpeg2.c | 12 ++++++++++++
- 2 files changed, 13 insertions(+)
-
-diff --git a/libavcodec/dxva2.h b/libavcodec/dxva2.h
-index fc99560..16a6994 100644
---- a/libavcodec/dxva2.h
-+++ b/libavcodec/dxva2.h
-@@ -66,6 +66,7 @@ struct dxva_context {
- * Private to the FFmpeg AVHWAccel implementation
- */
- unsigned report_id;
-+ unsigned last_slice_count;
- };
-
- #endif /* AVCODEC_DXVA_H */
-diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
-index 8ba83b6..90507f9 100644
---- a/libavcodec/dxva2_mpeg2.c
-+++ b/libavcodec/dxva2_mpeg2.c
-@@ -222,6 +222,16 @@
- ctx_pic->slice_count = 0;
- ctx_pic->bitstream_size = 0;
- ctx_pic->bitstream = NULL;
-+
-+ if (ctx->last_slice_count > 0)
-+ {
-+ ctx_pic->slice = av_fast_realloc(NULL,
-+ &ctx_pic->slice_alloc,
-+ ctx->last_slice_count * sizeof(DXVA_SliceInfo));
-+ if (!ctx_pic->slice)
-+ return -1;
-+ }
-+
- return 0;
- }
-
-@@ -251,6 +261,7 @@
- struct MpegEncContext *s = avctx->priv_data;
- struct dxva2_picture_context *ctx_pic =
- s->current_picture_ptr->f.hwaccel_picture_private;
-+ struct dxva_context *ctx = avctx->hwaccel_context;
- int ret;
-
- if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
-@@ -261,6 +272,8 @@
- commit_bitstream_and_slice_buffer);
- if (!ret)
- ff_mpeg_draw_horiz_band(s, 0, avctx->height);
-+
-+ ctx->last_slice_count = ctx_pic->slice_count;
- return ret;
- }
-
---
-1.7.9.4
-
diff --git a/lib/ffmpeg/patches/0062-backport-dxva2-bump-max-number-of-slices.patch b/lib/ffmpeg/patches/0062-backport-dxva2-bump-max-number-of-slices.patch
new file mode 100644
index 0000000000..9d0e5cbc40
--- /dev/null
+++ b/lib/ffmpeg/patches/0062-backport-dxva2-bump-max-number-of-slices.patch
@@ -0,0 +1,28 @@
+From bceeccc648baf94a02b7b2c53e44bf77a47773ef Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker <fernetmenta@online.de>
+Date: Mon, 27 Jan 2014 08:16:13 +0100
+Subject: [PATCH] dxva2: bump maximum number of slieces for mpeg2
+
+Suggested by heleppkes on https://trac.ffmpeg.org/ticket/3133
+
+Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
+---
+ libavcodec/dxva2_mpeg2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
+index 1827dd5..e2f6b70 100644
+--- a/libavcodec/dxva2_mpeg2.c
++++ b/libavcodec/dxva2_mpeg2.c
+@@ -22,7 +22,7 @@
+
+ #include "dxva2_internal.h"
+
+-#define MAX_SLICES (SLICE_MAX_START_CODE - SLICE_MIN_START_CODE + 1)
++#define MAX_SLICES 1024
+ struct dxva2_picture_context {
+ DXVA_PictureParameters pp;
+ DXVA_QmatrixData qm;
+--
+1.8.5.1
+
diff --git a/project/Win32BuildSetup/buildpvraddons.bat b/project/Win32BuildSetup/buildpvraddons.bat
index 7a4df2ec84..699c24f126 100644
--- a/project/Win32BuildSetup/buildpvraddons.bat
+++ b/project/Win32BuildSetup/buildpvraddons.bat
@@ -9,7 +9,7 @@ SET DEPS_DIR=..\BuildDependencies
SET TMP_DIR=%DEPS_DIR%\tmp
SET LIBNAME=xbmc-pvr-addons
-SET VERSION=31558d6e0216f9765215bb91354b312cbb2f397c
+SET VERSION=af29425b1e171419d72fb3a0475a10f4a862f0b7
SET SOURCE=%LIBNAME%
SET GIT_URL=git://github.com/opdenkamp/%LIBNAME%.git
SET SOURCE_DIR=%TMP_DIR%\%SOURCE%
diff --git a/tools/depends/target/xbmc-pvr-addons/Makefile b/tools/depends/target/xbmc-pvr-addons/Makefile
index 72cc7292fc..36128de391 100644
--- a/tools/depends/target/xbmc-pvr-addons/Makefile
+++ b/tools/depends/target/xbmc-pvr-addons/Makefile
@@ -2,7 +2,7 @@ include ../../Makefile.include
#DEPS= ../../Makefile.include Makefile
LIBNAME=xbmc-pvr-addons
-VERSION=31558d6e0216f9765215bb91354b312cbb2f397c
+VERSION=af29425b1e171419d72fb3a0475a10f4a862f0b7
GIT_DIR=$(TARBALLS_LOCATION)/$(LIBNAME).git
BASE_URL=git://github.com/opdenkamp/$(LIBNAME).git
DYLIB=$(PLATFORM)/addons/pvr.demo/.libs/libpvrdemo-addon.so
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
index 981a2c36e3..e20fd43cf4 100644
--- a/xbmc/addons/Addon.cpp
+++ b/xbmc/addons/Addon.cpp
@@ -315,8 +315,7 @@ bool CAddon::MeetsVersion(const AddonVersion &version) const
// if the addon is one of xbmc's extension point definitions (addonid starts with "xbmc.")
// and the minversion is "0.0.0" i.e. no <backwards-compatibility> tag has been specified
// we need to assume that the current version is not backwards-compatible and therefore check against the actual version
- if (StringUtils::StartsWithNoCase(m_props.id, "xbmc.") &&
- (strlen(m_props.minversion.c_str()) == 0 || StringUtils::EqualsNoCase(m_props.minversion.c_str(), "0.0.0")))
+ if (StringUtils::StartsWithNoCase(m_props.id, "xbmc.") && m_props.minversion.empty())
return m_props.version == version;
return m_props.minversion <= version && version <= m_props.version;
diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp
index 75e80c10fd..524895a244 100644
--- a/xbmc/addons/AddonDatabase.cpp
+++ b/xbmc/addons/AddonDatabase.cpp
@@ -181,6 +181,39 @@ int CAddonDatabase::AddAddon(const AddonPtr& addon,
return -1;
}
+AddonVersion CAddonDatabase::GetAddonVersion(const std::string &id)
+{
+ AddonVersion maxversion("0.0.0");
+ try
+ {
+ if (NULL == m_pDB.get()) return maxversion;
+ if (NULL == m_pDS2.get()) return maxversion;
+
+ // there may be multiple addons with this id (eg from different repositories) in the database,
+ // so we want to retrieve the latest version. Order by version won't work as the database
+ // won't know that 1.10 > 1.2, so grab them all and order outside
+ CStdString sql = PrepareSQL("select version from addon where addonID='%s'",id.c_str());
+ m_pDS2->query(sql.c_str());
+
+ if (m_pDS2->eof())
+ return maxversion;
+
+ while (!m_pDS2->eof())
+ {
+ AddonVersion version(m_pDS2->fv(0).get_asString());
+ if (version > maxversion)
+ maxversion = version;
+ m_pDS2->next();
+ }
+ return maxversion;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
+ }
+ return maxversion;
+}
+
bool CAddonDatabase::GetAddon(const CStdString& id, AddonPtr& addon)
{
try
@@ -242,49 +275,56 @@ bool CAddonDatabase::GetRepoForAddon(const CStdString& addonID, CStdString& repo
return false;
}
-bool CAddonDatabase::GetAddon(int id, AddonPtr& addon)
+bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS2.get()) return false;
- CStdString sql = PrepareSQL("select * from addon where id=%i",id);
+ std::string sql = "SELECT addon.*,"
+ " broken.reason,"
+ " addonextra.key, addonextra.value,"
+ " dependencies.addon, dependencies.version, dependencies.optional"
+ " FROM addon"
+ " LEFT JOIN broken"
+ " ON broken.addonID = addon.addonID"
+ " LEFT JOIN addonextra"
+ " ON addonextra.id = addon.id"
+ " LEFT JOIN dependencies"
+ " ON dependencies.id = addon.id";
+
+ sql += PrepareSQL(" WHERE addon.id=%i", id);
+
m_pDS2->query(sql.c_str());
if (!m_pDS2->eof())
{
- AddonProps props(m_pDS2->fv("addonID" ).get_asString(),
- TranslateType(m_pDS2->fv("type").get_asString()),
- m_pDS2->fv("version").get_asString(),
- m_pDS2->fv("minversion").get_asString());
- props.name = m_pDS2->fv("name").get_asString();
- props.summary = m_pDS2->fv("summary").get_asString();
- props.description = m_pDS2->fv("description").get_asString();
- props.changelog = m_pDS2->fv("changelog").get_asString();
- props.path = m_pDS2->fv("path").get_asString();
- props.icon = m_pDS2->fv("icon").get_asString();
- props.fanart = m_pDS2->fv("fanart").get_asString();
- props.author = m_pDS2->fv("author").get_asString();
- props.disclaimer = m_pDS2->fv("disclaimer").get_asString();
- sql = PrepareSQL("select reason from broken where addonID='%s'",props.id.c_str());
- m_pDS2->query(sql.c_str());
- if (!m_pDS2->eof())
- props.broken = m_pDS2->fv(0).get_asString();
-
- sql = PrepareSQL("select key,value from addonextra where id=%i", id);
- m_pDS2->query(sql.c_str());
- while (!m_pDS2->eof())
- {
- props.extrainfo.insert(make_pair(m_pDS2->fv(0).get_asString(), m_pDS2->fv(1).get_asString()));
- m_pDS2->next();
- }
-
- sql = PrepareSQL("select addon,version,optional from dependencies where id=%i", id);
- m_pDS2->query(sql.c_str());
- while (!m_pDS2->eof())
+ const dbiplus::query_data &data = m_pDS2->get_result_set().records;
+ const dbiplus::sql_record* const record = data[0];
+ AddonProps props(record->at(addon_addonID).get_asString(),
+ TranslateType(record->at(addon_type).get_asString()),
+ record->at(addon_version).get_asString(),
+ record->at(addon_minversion).get_asString());
+ props.name = record->at(addon_name).get_asString();
+ props.summary = record->at(addon_summary).get_asString();
+ props.description = record->at(addon_description).get_asString();
+ props.changelog = record->at(addon_changelog).get_asString();
+ props.path = record->at(addon_path).get_asString();
+ props.icon = record->at(addon_icon).get_asString();
+ props.fanart = record->at(addon_fanart).get_asString();
+ props.author = record->at(addon_author).get_asString();
+ props.disclaimer = record->at(addon_disclaimer).get_asString();
+ props.broken = record->at(broken_reason).get_asString();
+
+ /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
+ extrainfo and dependencies are maps, so insert() will insert the first instance only */
+ for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
{
- props.dependencies.insert(make_pair(m_pDS2->fv(0).get_asString(), make_pair(AddonVersion(m_pDS2->fv(1).get_asString()), m_pDS2->fv(2).get_asBool())));
- m_pDS2->next();
+ const dbiplus::sql_record* const record = *i;
+ if (!record->at(addonextra_key).get_asString().empty())
+ props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
+ if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
+ props.dependencies.insert(make_pair(record->at(dependencies_addon).get_asString(), make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
}
addon = CAddonMgr::AddonFromProps(props);
@@ -310,10 +350,8 @@ bool CAddonDatabase::GetAddons(VECADDONS& addons)
m_pDS->query(sql.c_str());
while (!m_pDS->eof())
{
- sql = PrepareSQL("select id from addon where addonID='%s' order by version desc",m_pDS->fv(0).get_asString().c_str());
- m_pDS2->query(sql.c_str());
AddonPtr addon;
- if (GetAddon(m_pDS2->fv(0).get_asInt(),addon))
+ if (GetAddon(m_pDS->fv(0).get_asString(),addon))
addons.push_back(addon);
m_pDS->next();
}
@@ -519,7 +557,7 @@ bool CAddonDatabase::Search(const CStdString& search, VECADDONS& addons)
if (NULL == m_pDS.get()) return false;
CStdString strSQL;
- strSQL=PrepareSQL("SELECT id FROM addon WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", search.c_str(), search.c_str(), search.c_str());
+ strSQL=PrepareSQL("SELECT addonID FROM addon WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", search.c_str(), search.c_str(), search.c_str());
CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
if (!m_pDS->query(strSQL.c_str())) return false;
@@ -528,7 +566,7 @@ bool CAddonDatabase::Search(const CStdString& search, VECADDONS& addons)
while (!m_pDS->eof())
{
AddonPtr addon;
- GetAddon(m_pDS->fv(0).get_asInt(),addon);
+ GetAddon(m_pDS->fv(0).get_asString(),addon);
if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
addons.push_back(addon);
m_pDS->next();
@@ -629,26 +667,11 @@ bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = t
bool CAddonDatabase::BreakAddon(const CStdString &addonID, const CStdString& reason)
{
- try
- {
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS.get()) return false;
-
- CStdString sql = PrepareSQL("delete from broken where addonID='%s'", addonID.c_str());
- m_pDS->exec(sql);
-
- if (!reason.empty())
- { // broken
- sql = PrepareSQL("insert into broken(id, addonID, reason) values(NULL, '%s', '%s')", addonID.c_str(),reason.c_str());
- m_pDS->exec(sql);
- }
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
- }
- return false;
+ if (reason.empty())
+ return ExecuteQuery(PrepareSQL("DELETE FROM broken WHERE addonID='%s'", addonID.c_str()));
+ else
+ return ExecuteQuery(PrepareSQL("REPLACE INTO broken(addonID, reason) VALUES('%s', '%s')",
+ addonID.c_str(), reason.c_str()));
}
bool CAddonDatabase::HasAddon(const CStdString &addonID)
@@ -689,24 +712,7 @@ bool CAddonDatabase::IsSystemPVRAddonEnabled(const CStdString &addonID)
CStdString CAddonDatabase::IsAddonBroken(const CStdString &addonID)
{
- try
- {
- if (NULL == m_pDB.get()) return "";
- if (NULL == m_pDS.get()) return "";
-
- CStdString sql = PrepareSQL("select reason from broken where addonID='%s'", addonID.c_str());
- m_pDS->query(sql.c_str());
- CStdString ret;
- if (!m_pDS->eof())
- ret = m_pDS->fv(0).get_asString();
- m_pDS->close();
- return ret;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
- }
- return "";
+ return GetSingleValue(PrepareSQL("SELECT reason FROM broken WHERE addonID='%s'", addonID.c_str()));
}
bool CAddonDatabase::HasDisabledAddons()
diff --git a/xbmc/addons/AddonDatabase.h b/xbmc/addons/AddonDatabase.h
index 76ad91db90..0901a0b73f 100644
--- a/xbmc/addons/AddonDatabase.h
+++ b/xbmc/addons/AddonDatabase.h
@@ -34,7 +34,9 @@ public:
int AddAddon(const ADDON::AddonPtr& item, int idRepo);
bool GetAddon(const CStdString& addonID, ADDON::AddonPtr& addon);
bool GetAddons(ADDON::VECADDONS& addons);
- bool GetAddon(int id, ADDON::AddonPtr& addon);
+
+ /*! \brief grab the (largest) add-on version for an add-on */
+ ADDON::AddonVersion GetAddonVersion(const std::string &id);
/*! \brief Grab the repository from which a given addon came
\param addonID - the id of the addon in question
@@ -137,5 +139,33 @@ protected:
virtual bool UpdateOldVersion(int version);
virtual int GetMinVersion() const { return 16; }
const char *GetBaseDBName() const { return "Addons"; }
+
+ bool GetAddon(int id, ADDON::AddonPtr& addon);
+
+ /* keep in sync with the select in GetAddon */
+ enum _AddonFields
+ {
+ addon_id=0,
+ addon_type,
+ addon_name,
+ addon_summary,
+ addon_description,
+ addon_stars,
+ addon_path,
+ addon_addonID,
+ addon_icon,
+ addon_version,
+ addon_changelog,
+ addon_fanart,
+ addon_author,
+ addon_disclaimer,
+ addon_minversion,
+ broken_reason,
+ addonextra_key,
+ addonextra_value,
+ dependencies_addon,
+ dependencies_version,
+ dependencies_optional
+ } AddonFields;
};
diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp
index 73562b4955..ccc8fdfcdf 100644
--- a/xbmc/addons/AddonInstaller.cpp
+++ b/xbmc/addons/AddonInstaller.cpp
@@ -307,20 +307,22 @@ void CAddonInstaller::InstallFromXBMCRepo(const set<CStdString> &addonIDs)
Install(*i);
}
-bool CAddonInstaller::CheckDependencies(const AddonPtr &addon)
+bool CAddonInstaller::CheckDependencies(const AddonPtr &addon, CAddonDatabase *database /* = NULL */)
{
std::vector<std::string> preDeps;
preDeps.push_back(addon->ID());
- return CheckDependencies(addon, preDeps);
+ CAddonDatabase localDB;
+ if (!database)
+ database = &localDB;
+ return CheckDependencies(addon, preDeps, *database);
}
bool CAddonInstaller::CheckDependencies(const AddonPtr &addon,
- std::vector<std::string>& preDeps)
+ std::vector<std::string>& preDeps, CAddonDatabase &database)
{
if (!addon.get())
return true; // a NULL addon has no dependencies
ADDONDEPS deps = addon->GetDeps();
- CAddonDatabase database;
database.Open();
for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
{
@@ -334,6 +336,7 @@ bool CAddonInstaller::CheckDependencies(const AddonPtr &addon,
if (!database.GetAddon(addonID, dep) || !dep->MeetsVersion(version))
{ // we don't have it in a repo, or we have it but the version isn't good enough, so dep isn't satisfied.
CLog::Log(LOGDEBUG, "Addon %s requires %s version %s which is not available", addon->ID().c_str(), addonID.c_str(), version.c_str());
+ database.Close();
return false;
}
}
@@ -341,11 +344,15 @@ bool CAddonInstaller::CheckDependencies(const AddonPtr &addon,
// TODO: should we assume that installed deps are OK?
if (dep && std::find(preDeps.begin(), preDeps.end(), dep->ID()) == preDeps.end())
{
- if (!CheckDependencies(dep, preDeps))
+ if (!CheckDependencies(dep, preDeps, database))
+ {
+ database.Close();
return false;
+ }
preDeps.push_back(dep->ID());
}
}
+ database.Close();
return true;
}
diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h
index 150541afc8..eb8ae11db9 100644
--- a/xbmc/addons/AddonInstaller.h
+++ b/xbmc/addons/AddonInstaller.h
@@ -24,6 +24,8 @@
#include "utils/Stopwatch.h"
#include "threads/Event.h"
+class CAddonDatabase;
+
class CAddonInstaller : public IJobCallback
{
public:
@@ -68,9 +70,10 @@ public:
Iterates through the addon's dependencies, checking they're installed or installable.
Each dependency must also satisfies CheckDependencies in turn.
\param addon the addon to check
+ \param database the database instance to update. Defaults to NULL.
\return true if dependencies are available, false otherwise.
*/
- bool CheckDependencies(const ADDON::AddonPtr &addon);
+ bool CheckDependencies(const ADDON::AddonPtr &addon, CAddonDatabase *database = NULL);
/*! \brief Update all repositories (if needed)
Runs through all available repositories and queues an update of them if they
@@ -127,10 +130,11 @@ private:
Each dependency must also satisfies CheckDependencies in turn.
\param addon the addon to check
\param preDeps previous dependencies encountered during recursion. aids in avoiding infinite recursion
+ \param database database instance to update
\return true if dependencies are available, false otherwise.
*/
bool CheckDependencies(const ADDON::AddonPtr &addon,
- std::vector<std::string>& preDeps);
+ std::vector<std::string>& preDeps, CAddonDatabase &database);
void PrunePackageCache();
int64_t EnumeratePackageFolder(std::map<CStdString,CFileItemList*>& result);
diff --git a/xbmc/addons/AddonVersion.cpp b/xbmc/addons/AddonVersion.cpp
index ba22ee1f43..5a6fb4d3ec 100644
--- a/xbmc/addons/AddonVersion.cpp
+++ b/xbmc/addons/AddonVersion.cpp
@@ -124,6 +124,11 @@ namespace ADDON
&& CompareComponent(Revision(), other.Revision()) == 0;
}
+ bool AddonVersion::empty() const
+ {
+ return m_originalVersion.empty() || m_originalVersion == "0.0.0";
+ }
+
CStdString AddonVersion::Print() const
{
return StringUtils::Format("%s %s", g_localizeStrings.Get(24051).c_str(), m_originalVersion.c_str());
diff --git a/xbmc/addons/AddonVersion.h b/xbmc/addons/AddonVersion.h
index a4ba0f2ad7..f804278169 100644
--- a/xbmc/addons/AddonVersion.h
+++ b/xbmc/addons/AddonVersion.h
@@ -53,6 +53,7 @@ namespace ADDON
bool operator==(const AddonVersion& other) const;
CStdString Print() const;
const char *c_str() const { return m_originalVersion.c_str(); };
+ bool empty() const;
static bool SplitFileName(CStdString& ID, CStdString& version,
const CStdString& filename);
diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp
index addfb72480..aed7259020 100644
--- a/xbmc/addons/Repository.cpp
+++ b/xbmc/addons/Repository.cpp
@@ -242,9 +242,11 @@ bool CRepositoryUpdateJob::DoWork()
// check for updates
CAddonDatabase database;
database.Open();
-
+ database.BeginMultipleExecute();
+
CTextureDatabase textureDB;
textureDB.Open();
+ textureDB.BeginMultipleExecute();
for (map<string, AddonPtr>::const_iterator i = addons.begin(); i != addons.end(); ++i)
{
// manager told us to feck off
@@ -252,7 +254,7 @@ bool CRepositoryUpdateJob::DoWork()
break;
AddonPtr newAddon = i->second;
- bool deps_met = CAddonInstaller::Get().CheckDependencies(newAddon);
+ bool deps_met = CAddonInstaller::Get().CheckDependencies(newAddon, &database);
if (!deps_met && newAddon->Props().broken.empty())
newAddon->Props().broken = "DEPSNOTMET";
@@ -290,12 +292,8 @@ bool CRepositoryUpdateJob::DoWork()
// Check if we should mark the add-on as broken. We may have a newer version
// of this add-on in the database or installed - if so, we keep it unbroken.
- bool haveNewer = addon && addon->Version() > newAddon->Version();
- if (!haveNewer)
- {
- AddonPtr dbAddon;
- haveNewer = database.GetAddon(newAddon->ID(), dbAddon) && dbAddon->Version() > newAddon->Version();
- }
+ bool haveNewer = (addon && addon->Version() > newAddon->Version()) ||
+ database.GetAddonVersion(newAddon->ID()) > newAddon->Version();
if (!haveNewer)
{
if (!newAddon->Props().broken.empty())
@@ -315,6 +313,8 @@ bool CRepositoryUpdateJob::DoWork()
database.BreakAddon(newAddon->ID(), newAddon->Props().broken);
}
}
+ database.CommitMultipleExecute();
+ textureDB.CommitMultipleExecute();
return true;
}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
index 14ac2e83cf..da3216ac13 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
@@ -282,7 +282,10 @@ static pa_channel_map AEChannelMapToPAChannel(CAEChannelInfo info)
{
pos = AEChannelToPAChannel(info[i]);
if(pos != PA_CHANNEL_POSITION_INVALID)
- map.channels++;
+ {
+ // remember channel name and increase channel count
+ map.map[map.channels++] = pos;
+ }
}
return map;
}
@@ -443,7 +446,10 @@ bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
info[0] = pa_format_info_new();
info[0]->encoding = AEFormatToPulseEncoding(format.m_dataFormat);
if(!passthrough)
+ {
pa_format_info_set_sample_format(info[0], AEFormatToPulseFormat(format.m_dataFormat));
+ pa_format_info_set_channel_map(info[0], &map);
+ }
pa_format_info_set_channels(info[0], m_Channels);
// PA requires m_encodedRate in order to do EAC3
@@ -473,7 +479,7 @@ bool CAESinkPULSE::Initialize(AEAudioFormat &format, std::string &device)
pa_sample_spec spec;
#if PA_CHECK_VERSION(2,0,0)
- pa_format_info_to_sample_spec(info[0], &spec, &map);
+ pa_format_info_to_sample_spec(info[0], &spec, NULL);
#else
spec.rate = (AEFormatToPulseEncoding(format.m_dataFormat) == PA_ENCODING_EAC3_IEC61937) ? 4 * samplerate : samplerate;
spec.format = AEFormatToPulseFormat(format.m_dataFormat);
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
index 72beba4518..d8e28ae085 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
@@ -55,7 +55,7 @@ void CAESinkPi::SetAudioDest()
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
OMX_INIT_STRUCTURE(audioDest);
- if (CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
strncpy((char *)audioDest.sName, "local", strlen("local"));
else
strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
index 70f75fb329..b70ab916b4 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
@@ -58,6 +58,7 @@ static bool CanSurfaceRenderWhiteList(const std::string &name)
"OMX.Nvidia",
"OMX.rk",
"OMX.qcom",
+ "OMX.Intel",
NULL
};
for (const char **ptr = cansurfacerender_decoders; *ptr; ptr++)
@@ -916,9 +917,9 @@ void CDVDVideoCodecAndroidMediaCodec::OutputFormatChanged(void)
else
{
// Android device quirks and fixes
- if (stride <= 0)
+ if (stride <= width)
stride = width;
- if (slice_height <= 0)
+ if (slice_height <= height)
{
slice_height = height;
if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar)
diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp
index 1f780f5b52..c6674ad84b 100644
--- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamFFmpeg.cpp
@@ -19,6 +19,10 @@
*/
#include "DVDInputStreamFFmpeg.h"
+#include "xbmc/playlists/PlayListM3U.h"
+#include "settings/Settings.h"
+#include "Util.h"
+#include "utils/log.h"
using namespace XFILE;
@@ -46,6 +50,21 @@ bool CDVDInputStreamFFmpeg::IsEOF()
bool CDVDInputStreamFFmpeg::Open(const char* strFile, const std::string& content)
{
+ CFileItem item(strFile, false);
+ if (item.IsInternetStream() && item.IsType(".m3u8"))
+ {
+ // get the available bandwidth and determine the most appropriate stream
+ int bandwidth = CSettings::Get().GetInt("network.bandwidth");
+ if(bandwidth <= 0)
+ bandwidth = INT_MAX;
+ std::string selected = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(strFile, bandwidth);
+ if (selected.compare(strFile) != 0)
+ {
+ CLog::Log(LOGINFO, "CDVDInputStreamFFmpeg: Auto-selecting %s based on configured bandwidth.", selected.c_str());
+ strFile = selected.c_str();
+ }
+ }
+
if (!CDVDInputStream::Open(strFile, content))
return false;
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 8059f666fa..19ba19f56d 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -662,20 +662,6 @@ bool CDVDPlayer::OpenInputStream()
m_filename = g_mediaManager.TranslateDevicePath("");
}
- // before creating the input stream, if this is an HLS playlist then get the
- // most appropriate bitrate based on our network settings
- // ensure to strip off the url options by using a temp CURL object
- if (StringUtils::StartsWith(filename, "http://") &&
- StringUtils::EndsWith(CURL(filename).GetFileName(), ".m3u8"))
- {
- // get the available bandwidth (as per user settings)
- int maxrate = CSettings::Get().GetInt("network.bandwidth");
- if(maxrate <= 0)
- maxrate = INT_MAX;
-
- // determine the most appropriate stream
- m_filename = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(m_filename, (size_t)maxrate);
- }
m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_filename, m_mimetype);
if(m_pInputStream == NULL)
{
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index 5e5efea339..dd804124dc 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -117,12 +117,12 @@ bool COMXAudio::PortSettingsChanged()
if(!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
+ if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
{
if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") != "Pi:Analogue")
+ if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue")
{
if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
@@ -470,7 +470,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
// ignore layout setting for analogue
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
+ if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
layout = PCM_LAYOUT_2_0;
// force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp
index c039d80f66..a26183ff38 100644
--- a/xbmc/cores/omxplayer/OMXPlayer.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp
@@ -708,19 +708,6 @@ bool COMXPlayer::OpenInputStream()
m_filename = g_mediaManager.TranslateDevicePath("");
}
- // before creating the input stream, if this is an HLS playlist then get the
- // most appropriate bitrate based on our network settings
- // ensure to strip off the url options by using a temp CURL object
- if (StringUtils::StartsWith(filename, "http://") && StringUtils::EndsWith(CURL(filename).GetFileName(), ".m3u8"))
- {
- // get the available bandwidth (as per user settings)
- int maxrate = CSettings::Get().GetInt("network.bandwidth");
- if(maxrate <= 0)
- maxrate = INT_MAX;
-
- // determine the most appropriate stream
- m_filename = PLAYLIST::CPlayListM3U::GetBestBandwidthStream(m_filename, (size_t)maxrate);
- }
m_pInputStream = CDVDFactoryInputStream::CreateInputStream(this, m_filename, m_mimetype);
if(m_pInputStream == NULL)
{
diff --git a/xbmc/cores/paplayer/CodecFactory.cpp b/xbmc/cores/paplayer/CodecFactory.cpp
index 6d3d229c69..995c4be257 100644
--- a/xbmc/cores/paplayer/CodecFactory.cpp
+++ b/xbmc/cores/paplayer/CodecFactory.cpp
@@ -109,6 +109,8 @@ ICodec* CodecFactory::CreateCodec(const CStdString& strFileType)
#endif
else if (strFileType.Equals("tta"))
return new DVDPlayerCodec();
+ else if (strFileType.Equals("tak"))
+ return new DVDPlayerCodec();
return NULL;
}
diff --git a/xbmc/cores/paplayer/FLACcodec.cpp b/xbmc/cores/paplayer/FLACcodec.cpp
index cea984493b..2c4d93f103 100644
--- a/xbmc/cores/paplayer/FLACcodec.cpp
+++ b/xbmc/cores/paplayer/FLACcodec.cpp
@@ -208,7 +208,10 @@ FLAC__StreamDecoderReadStatus FLACCodec::DecoderReadCallback(const FLAC__StreamD
*bytes=pThis->m_file.Read(buffer, *bytes);
- return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ if (*bytes==0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
FLAC__StreamDecoderSeekStatus FLACCodec::DecoderSeekCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp
index a98ec57f73..c08f823694 100644
--- a/xbmc/cores/paplayer/PAPlayer.cpp
+++ b/xbmc/cores/paplayer/PAPlayer.cpp
@@ -520,6 +520,18 @@ bool PAPlayer::CloseFile(bool reopen)
/* wait for the thread to terminate */
StopThread(true);//true - wait for end of thread
+
+ // wait for any pending jobs to complete
+ {
+ CSharedLock lock(m_streamsLock);
+ while (m_jobCounter > 0)
+ {
+ lock.Leave();
+ m_jobEvent.WaitMSec(100);
+ lock.Enter();
+ }
+ }
+
return true;
}
@@ -553,17 +565,6 @@ void PAPlayer::Process()
GetTimeInternal(); //update for GUI
}
- // wait for any pending jobs to complete
- {
- CSharedLock lock(m_streamsLock);
- while (m_jobCounter > 0)
- {
- lock.Leave();
- m_jobEvent.WaitMSec(100);
- lock.Enter();
- }
- }
-
if(m_isFinished && !m_bStop)
m_callback.OnPlayBackEnded();
else
diff --git a/xbmc/dbwrappers/Database.cpp b/xbmc/dbwrappers/Database.cpp
index 8128435412..1deb4c9ee6 100644
--- a/xbmc/dbwrappers/Database.cpp
+++ b/xbmc/dbwrappers/Database.cpp
@@ -106,6 +106,7 @@ CDatabase::CDatabase(void)
m_openCount = 0;
m_sqlite = true;
m_bMultiWrite = false;
+ m_multipleExecute = false;
}
CDatabase::~CDatabase(void)
@@ -193,8 +194,35 @@ bool CDatabase::DeleteValues(const CStdString &strTable, const Filter &filter /*
return ExecuteQuery(strQuery);
}
+bool CDatabase::BeginMultipleExecute()
+{
+ m_multipleExecute = true;
+ return true;
+}
+
+bool CDatabase::CommitMultipleExecute()
+{
+ m_multipleExecute = false;
+ BeginTransaction();
+ for (std::vector<std::string>::const_iterator i = m_multipleQueries.begin(); i != m_multipleQueries.end(); ++i)
+ {
+ if (!ExecuteQuery(*i))
+ {
+ RollbackTransaction();
+ return false;
+ }
+ }
+ return true;
+}
+
bool CDatabase::ExecuteQuery(const CStdString &strQuery)
{
+ if (m_multipleExecute)
+ {
+ m_multipleQueries.push_back(strQuery);
+ return true;
+ }
+
bool bReturn = false;
try
@@ -547,6 +575,7 @@ void CDatabase::Close()
}
m_openCount = 0;
+ m_multipleExecute = false;
if (NULL == m_pDB.get() ) return ;
if (NULL != m_pDS.get()) m_pDS->close();
diff --git a/xbmc/dbwrappers/Database.h b/xbmc/dbwrappers/Database.h
index 9dbe4e7e60..a270f0821a 100644
--- a/xbmc/dbwrappers/Database.h
+++ b/xbmc/dbwrappers/Database.h
@@ -102,8 +102,11 @@ public:
/*!
* @brief Execute a query that does not return any result.
+ * Note that if BeginMultipleExecute() has been called, the
+ * query will be queued until CommitMultipleExecute() is called.
* @param strQuery The query to execute.
* @return True if the query was executed successfully, false otherwise.
+ * @sa BeginMultipleExecute, CommitMultipleExecute
*/
bool ExecuteQuery(const CStdString &strQuery);
@@ -116,6 +119,26 @@ public:
bool ResultQuery(const CStdString &strQuery);
/*!
+ * @brief Start a multiple execution queue. Any ExecuteQuery() function
+ * following this call will be queued rather than executed until
+ * CommitMultipleExecute() is performed.
+ * NOTE: Queries that rely on any queued execute query will not
+ * function as expected during this period!
+ * @return true if we could start a multiple execution queue, false otherwise.
+ * @sa CommitMultipleExecute, ExecuteQuery
+ */
+ bool BeginMultipleExecute();
+
+ /*!
+ * @brief Commit the multiple execution queue to the database.
+ * Queries are performed within a transaction, and the transaction
+ * is rolled back should any one query fail.
+ * @return True if the queries were executed successfully, false otherwise.
+ * @sa BeginMultipleExecute, ExecuteQuery
+ */
+ bool CommitMultipleExecute();
+
+ /*!
* @brief Open a new dataset.
* @return True if the dataset was created successfully, false otherwise.
*/
@@ -171,4 +194,7 @@ private:
bool m_bMultiWrite; /*!< True if there are any queries in the queue, false otherwise */
unsigned int m_openCount;
+
+ bool m_multipleExecute;
+ std::vector<std::string> m_multipleQueries;
};
diff --git a/xbmc/dbwrappers/mysqldataset.cpp b/xbmc/dbwrappers/mysqldataset.cpp
index 436f564878..523e621511 100644
--- a/xbmc/dbwrappers/mysqldataset.cpp
+++ b/xbmc/dbwrappers/mysqldataset.cpp
@@ -155,7 +155,7 @@ int MysqlDatabase::connect(bool create_new) {
char sqlcmd[512];
int ret;
- sprintf(sqlcmd, "CREATE DATABASE `%s`", db.c_str());
+ sprintf(sqlcmd, "CREATE DATABASE `%s` CHARACTER SET utf8 COLLATE utf8_general_ci", db.c_str());
if ( (ret=query_with_reconnect(sqlcmd)) != MYSQL_OK )
{
throw DbErrors("Can't create new database: '%s' (%d)", db.c_str(), ret);
@@ -250,7 +250,7 @@ int MysqlDatabase::copy(const char *backup_name) {
}
// create the new database
- sprintf(sql, "CREATE DATABASE `%s`", backup_name);
+ sprintf(sql, "CREATE DATABASE `%s` CHARACTER SET utf8 COLLATE utf8_general_ci", backup_name);
if ( (ret=query_with_reconnect(sql)) != MYSQL_OK )
{
mysql_free_result(res);
@@ -1375,7 +1375,8 @@ int MysqlDataset::exec(const string &sql) {
}
// force the charset and collation to UTF-8
- if ( ci_find(qry, "CREATE TABLE") != string::npos )
+ if ( ci_find(qry, "CREATE TABLE") != string::npos
+ || ci_find(qry, "CREATE TEMPORARY TABLE") != string::npos )
{
qry += " CHARACTER SET utf8 COLLATE utf8_general_ci";
}
diff --git a/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp b/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
index 70e12ec583..27966fb5e9 100644
--- a/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
+++ b/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
@@ -325,7 +325,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
}
// sort the items
- items.Sort(SortByLabel, SortOrderAscending);
+ items.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
pDialog->Reset();
diff --git a/xbmc/guilib/GUIButtonControl.cpp b/xbmc/guilib/GUIButtonControl.cpp
index ce6a310940..d59062376a 100644
--- a/xbmc/guilib/GUIButtonControl.cpp
+++ b/xbmc/guilib/GUIButtonControl.cpp
@@ -137,8 +137,10 @@ void CGUIButtonControl::ProcessText(unsigned int currentTime)
m_label2.GetRenderRect() != label2RenderRect);
changed |= m_label2.SetColor(GetTextColor());
+ changed |= m_label2.Process(currentTime);
}
changed |= m_label.SetColor(GetTextColor());
+ changed |= m_label.Process(currentTime);
if (changed)
MarkDirtyRegion();
}
diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp
index e144554b06..0f14c1ad41 100644
--- a/xbmc/music/MusicDatabase.cpp
+++ b/xbmc/music/MusicDatabase.cpp
@@ -2498,10 +2498,13 @@ bool CMusicDatabase::CleanupArtists()
// (nested queries by Bobbin007)
// must be executed AFTER the song, album and their artist link tables are cleaned.
// don't delete the "Various Artists" string
- CStdString strSQL = "delete from artist where idArtist not in (select idArtist from song_artist)";
- strSQL += " and idArtist not in (select idArtist from album_artist)";
- CStdString strSQL2;
- m_pDS->exec(strSQL.c_str());
+
+ // Create temp table to avoid 1442 trigger hell on mysql
+ m_pDS->exec("CREATE TEMPORARY TABLE tmp_delartists (idArtist integer)");
+ m_pDS->exec("INSERT INTO tmp_delartists select idArtist from song_artist");
+ m_pDS->exec("INSERT INTO tmp_delartists select idArtist from album_artist");
+ m_pDS->exec("delete from artist where idArtist not in (select idArtist from tmp_delartists)");
+ m_pDS->exec("DROP TABLE tmp_delartists");
return true;
}
catch (...)
diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp
index 96acecbe28..6841a61430 100644
--- a/xbmc/network/upnp/UPnPInternal.cpp
+++ b/xbmc/network/upnp/UPnPInternal.cpp
@@ -76,6 +76,22 @@ EClientQuirks GetClientQuirks(const PLT_HttpRequestContext* context)
}
/*----------------------------------------------------------------------
+| GetMediaControllerQuirks
++---------------------------------------------------------------------*/
+EMediaControllerQuirks GetMediaControllerQuirks(const PLT_DeviceData *device)
+{
+ if (device == NULL)
+ return EMEDIACONTROLLERQUIRKS_NONE;
+
+ unsigned int quirks = 0;
+
+ if (device->m_Manufacturer.Find("Samsung Electronics") >= 0)
+ quirks |= EMEDIACONTROLLERQUIRKS_X_MKV;
+
+ return (EMediaControllerQuirks)quirks;
+}
+
+/*----------------------------------------------------------------------
| GetMimeType
+---------------------------------------------------------------------*/
NPT_String
diff --git a/xbmc/network/upnp/UPnPInternal.h b/xbmc/network/upnp/UPnPInternal.h
index a2e758394b..8e9c089d14 100644
--- a/xbmc/network/upnp/UPnPInternal.h
+++ b/xbmc/network/upnp/UPnPInternal.h
@@ -28,6 +28,7 @@
class CUPnPServer;
class CFileItem;
class CThumbLoader;
+class PLT_DeviceData;
class PLT_HttpRequestContext;
class PLT_MediaItemResource;
class PLT_MediaObject;
@@ -64,6 +65,16 @@ namespace UPNP
EClientQuirks GetClientQuirks(const PLT_HttpRequestContext* context);
+ enum EMediaControllerQuirks
+ {
+ EMEDIACONTROLLERQUIRKS_NONE = 0x00
+
+ /* Media Controller expects MIME type video/x-mkv instead of video/x-matroska (Samsung) */
+ , EMEDIACONTROLLERQUIRKS_X_MKV = 0x01
+ };
+
+ EMediaControllerQuirks GetMediaControllerQuirks(const PLT_DeviceData *device);
+
const char* GetMimeTypeFromExtension(const char* extension, const PLT_HttpRequestContext* context = NULL);
NPT_String GetMimeType(const CFileItem& item, const PLT_HttpRequestContext* context = NULL);
NPT_String GetMimeType(const char* filename, const PLT_HttpRequestContext* context = NULL);
diff --git a/xbmc/network/upnp/UPnPPlayer.cpp b/xbmc/network/upnp/UPnPPlayer.cpp
index 16ed23b9bf..72c7e96c89 100644
--- a/xbmc/network/upnp/UPnPPlayer.cpp
+++ b/xbmc/network/upnp/UPnPPlayer.cpp
@@ -217,6 +217,7 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, const CPlayerOptions& options,
NPT_Reference<PLT_MediaObject> obj;
NPT_String path(file.GetPath().c_str());
NPT_String tmp, resource;
+ EMediaControllerQuirks quirks = EMEDIACONTROLLERQUIRKS_NONE;
NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed);
@@ -232,12 +233,25 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, const CPlayerOptions& options,
tmp.Insert(didl_header, 0);
tmp.Append(didl_footer);
+ quirks = GetMediaControllerQuirks(m_delegate->m_device.AsPointer());
+ if (quirks & EMEDIACONTROLLERQUIRKS_X_MKV)
+ {
+ for (NPT_Cardinal i=0; i< obj->m_Resources.GetItemCount(); i++) {
+ if (obj->m_Resources[i].m_ProtocolInfo.GetContentType().Compare("video/x-matroska") == 0) {
+ NPT_String protocolInfo = obj->m_Resources[i].m_ProtocolInfo.ToString();
+ protocolInfo.Replace(":video/x-matroska:", ":video/x-mkv:");
+ obj->m_Resources[i].m_ProtocolInfo = PLT_ProtocolInfo(protocolInfo);
+ }
+ }
+ }
+
/* The resource uri's are stored in the Didl. We must choose the best resource
* for the playback device */
NPT_Cardinal res_index;
NPT_CHECK_LABEL_SEVERE(m_control->FindBestResource(m_delegate->m_device, *obj, res_index), failed);
+ timeout.Set(timeout.GetInitialTimeoutValue());
/* dlna specifies that a return code of 705 should be returned
* if TRANSPORT_STATE is not STOPPED or NO_MEDIA_PRESENT */
NPT_CHECK_LABEL_SEVERE(m_control->Stop(m_delegate->m_device
@@ -247,6 +261,7 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, const CPlayerOptions& options,
NPT_CHECK_LABEL_SEVERE(m_delegate->m_resstatus, failed);
+ timeout.Set(timeout.GetInitialTimeoutValue());
NPT_CHECK_LABEL_SEVERE(m_control->SetAVTransportURI(m_delegate->m_device
, m_delegate->m_instance
, obj->m_Resources[res_index].m_Uri
@@ -255,6 +270,7 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, const CPlayerOptions& options,
NPT_CHECK_LABEL_SEVERE(WaitOnEvent(m_delegate->m_resevent, timeout, dialog), failed);
NPT_CHECK_LABEL_SEVERE(m_delegate->m_resstatus, failed);
+ timeout.Set(timeout.GetInitialTimeoutValue());
NPT_CHECK_LABEL_SEVERE(m_control->Play(m_delegate->m_device
, m_delegate->m_instance
, "1"
@@ -264,6 +280,7 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, const CPlayerOptions& options,
/* wait for PLAYING state */
+ timeout.Set(timeout.GetInitialTimeoutValue());
do {
NPT_CHECK_LABEL_SEVERE(m_control->GetTransportInfo(m_delegate->m_device
, m_delegate->m_instance
diff --git a/xbmc/network/upnp/UPnPRenderer.cpp b/xbmc/network/upnp/UPnPRenderer.cpp
index 767e50694a..3737afff3a 100644
--- a/xbmc/network/upnp/UPnPRenderer.cpp
+++ b/xbmc/network/upnp/UPnPRenderer.cpp
@@ -157,6 +157,7 @@ CUPnPRenderer::SetupServices()
",http-get:*:video/xvid:*"
",http-get:*:video/x-divx:*"
",http-get:*:video/x-matroska:*"
+ ",http-get:*:video/x-mkv:*"
",http-get:*:video/x-ms-wmv:*"
",http-get:*:video/x-ms-avi:*"
",http-get:*:video/x-flv:*"
diff --git a/xbmc/playlists/PlayListM3U.cpp b/xbmc/playlists/PlayListM3U.cpp
index 11d2cd9ee3..6d9d3da918 100644
--- a/xbmc/playlists/PlayListM3U.cpp
+++ b/xbmc/playlists/PlayListM3U.cpp
@@ -261,10 +261,7 @@ CStdString CPlayListM3U::GetBestBandwidthStream(const CStdString &strFileName, s
// if any protocol options were set, restore them
subStreamUrl.SetProtocolOptions(playlistUrl.GetProtocolOptions());
- CStdString subStream = subStreamUrl.Get();
-
- CLog::Log(LOGINFO, "Auto-selecting %s based on configured bandwidth.", subStream.c_str());
- return subStream;
+ return subStreamUrl.Get();
}
std::map< CStdString, CStdString > CPlayListM3U::ParseStreamLine(const CStdString &streamLine)
diff --git a/xbmc/pvr/PVRManager.cpp b/xbmc/pvr/PVRManager.cpp
index 767012e76c..cc98c4359a 100644
--- a/xbmc/pvr/PVRManager.cpp
+++ b/xbmc/pvr/PVRManager.cpp
@@ -975,6 +975,8 @@ bool CPVRManager::OpenLiveStream(const CFileItem &channel)
CDateTime::GetCurrentDateTime().GetAsTime(tNow);
playingChannel->SetLastWatched(tNow);
bPersistChannel = true;
+
+ m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(playingChannel->IsRadio()));
}
}
@@ -1016,6 +1018,8 @@ void CPVRManager::CloseStream(void)
CDateTime::GetCurrentDateTime().GetAsTime(tNow);
channel->SetLastWatched(tNow);
bPersistChannel = true;
+
+ m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(channel->IsRadio()));
}
m_addons->CloseStream();
@@ -1218,6 +1222,8 @@ bool CPVRManager::PerformChannelSwitch(const CPVRChannel &channel, bool bPreview
time_t tNow;
CDateTime::GetCurrentDateTime().GetAsTime(tNow);
currentChannel->SetLastWatched(tNow);
+
+ m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(currentChannel->IsRadio()));
}
// store channel settings
diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp
index 47a4b2f3e9..3c76d1e731 100644
--- a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp
@@ -291,3 +291,16 @@ bool CPVRChannelGroupsContainer::CreateChannelEpgs(void)
return m_groupsRadio->CreateChannelEpgs() &&
m_groupsTV->CreateChannelEpgs();
}
+
+CPVRChannelGroupPtr CPVRChannelGroupsContainer::GetPreviousPlayedGroup(void)
+{
+ CSingleLock lock(m_critSection);
+ return m_lastPlayedGroups[0];
+}
+
+void CPVRChannelGroupsContainer::SetLastPlayedGroup(CPVRChannelGroupPtr group)
+{
+ CSingleLock lock(m_critSection);
+ m_lastPlayedGroups[0] = m_lastPlayedGroups[1];
+ m_lastPlayedGroups[1] = group;
+}
diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.h b/xbmc/pvr/channels/PVRChannelGroupsContainer.h
index 3edb9ea31b..e17d898e28 100644
--- a/xbmc/pvr/channels/PVRChannelGroupsContainer.h
+++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.h
@@ -188,6 +188,18 @@ namespace PVR
*/
bool CreateChannelEpgs(void);
+ /*!
+ * @brief Return the group which was previous played.
+ * @return The group which was previous played.
+ */
+ CPVRChannelGroupPtr GetPreviousPlayedGroup(void);
+
+ /*!
+ * @brief Set the last played group.
+ * @param The last played group
+ */
+ void SetLastPlayedGroup(CPVRChannelGroupPtr group);
+
protected:
/*!
* @brief Update the contents of all the groups in this container.
@@ -201,5 +213,6 @@ namespace PVR
CCriticalSection m_critSection;
bool m_bUpdateChannelsOnly;
bool m_bIsUpdating;
+ CPVRChannelGroupPtr m_lastPlayedGroups[2]; /*!< used to store the last played groups */
};
}
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 6980cc7e0b..462371e599 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -394,7 +394,7 @@ void CAdvancedSettings::Initialize()
m_databaseVideo.Reset();
m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2|.rss";
- m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.mod|.amf|.669|.dmf|.dsm|.far|.gdm|.imf|.it|.m15|.med|.okt|.s3m|.stm|.sfx|.ult|.uni|.xm|.sid|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.nsf|.spc|.gym|.adx|.dsp|.adp|.ymf|.ast|.afc|.hps|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.mid|.kar|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.cm3|.cms|.dlt|.brstm|.wtv|.mka";
+ m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.mod|.amf|.669|.dmf|.dsm|.far|.gdm|.imf|.it|.m15|.med|.okt|.s3m|.stm|.sfx|.ult|.uni|.xm|.sid|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.nsf|.spc|.gym|.adx|.dsp|.adp|.ymf|.ast|.afc|.hps|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.mid|.kar|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.cm3|.cms|.dlt|.brstm|.wtv|.mka|.tak";
m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.m3u8|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv|.rss|.mpls|.webm|.bdmv|.wtv";
m_subtitlesExtensions = ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.text|.ssa|.aqt|.jss|.ass|.idx|.ifo|.rar|.zip";
m_discStubExtensions = ".disc";
diff --git a/xbmc/video/dialogs/GUIDialogSubtitles.cpp b/xbmc/video/dialogs/GUIDialogSubtitles.cpp
index d6478afadd..6bf67a8435 100644
--- a/xbmc/video/dialogs/GUIDialogSubtitles.cpp
+++ b/xbmc/video/dialogs/GUIDialogSubtitles.cpp
@@ -31,6 +31,7 @@
#include "filesystem/SpecialProtocol.h"
#include "guilib/GUIImage.h"
#include "guilib/GUIKeyboardFactory.h"
+#include "guilib/Key.h"
#include "settings/MediaSettings.h"
#include "settings/Settings.h"
#include "settings/VideoSettings.h"
@@ -114,7 +115,9 @@ CGUIDialogSubtitles::~CGUIDialogSubtitles(void)
bool CGUIDialogSubtitles::OnMessage(CGUIMessage& message)
{
- if (message.GetMessage() == GUI_MSG_CLICKED)
+ if (message.GetMessage() == GUI_MSG_CLICKED &&
+ (message.GetParam1() == ACTION_SELECT_ITEM ||
+ message.GetParam1() == ACTION_MOUSE_LEFT_CLICK))
{
int iControl = message.GetSenderId();
diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
index bca5a63f96..03f1aa638c 100644
--- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
@@ -305,11 +305,14 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered;
if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
- m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
- m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency
- m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
- m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
- m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
+ if (!m_movieItem->HasProperty("totalepisodes"))
+ {
+ m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
+ m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency
+ m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
+ m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
+ m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
+ }
}
else if (type == VIDEODB_CONTENT_EPISODES)
{
diff --git a/xbmc/video/windows/GUIWindowFullScreen.cpp b/xbmc/video/windows/GUIWindowFullScreen.cpp
index d51e7f72c7..548d0ff3ea 100644
--- a/xbmc/video/windows/GUIWindowFullScreen.cpp
+++ b/xbmc/video/windows/GUIWindowFullScreen.cpp
@@ -236,34 +236,40 @@ bool CGUIWindowFullScreen::OnAction(const CAction &action)
{
if (g_application.CurrentFileItem().IsLiveTV())
{
- CPVRChannelPtr channel;
- int iChannelNumber = -1;
- g_PVRManager.GetCurrentChannel(channel);
+ CPVRChannelPtr playingChannel;
+ g_PVRManager.GetCurrentChannel(playingChannel);
if (action.GetID() == REMOTE_0)
{
- iChannelNumber = g_PVRManager.GetPreviousChannel();
- if (iChannelNumber > 0)
- CLog::Log(LOGDEBUG, "switch to channel number %d", iChannelNumber);
- else
- CLog::Log(LOGDEBUG, "no previous channel number found");
+ CPVRChannelGroupPtr group = g_PVRChannelGroups->GetPreviousPlayedGroup();
+ if (group)
+ {
+ g_PVRManager.SetPlayingGroup(group);
+ CFileItemPtr fileItem = group->GetLastPlayedChannel(playingChannel->ChannelID());
+ if (fileItem && fileItem->HasPVRChannelInfoTag())
+ {
+ CLog::Log(LOGDEBUG, "%s - switch to channel number %d", __FUNCTION__, fileItem->GetPVRChannelInfoTag()->ChannelNumber());
+ g_application.OnAction(CAction(ACTION_CHANNEL_SWITCH, (float) fileItem->GetPVRChannelInfoTag()->ChannelNumber()));
+ }
+ }
}
else
{
int autoCloseTime = CSettings::Get().GetBool("pvrplayback.confirmchannelswitch") ? 0 : g_advancedSettings.m_iPVRNumericChannelSwitchTimeout;
CStdString strChannel = StringUtils::Format("%i", action.GetID() - REMOTE_0);
if (CGUIDialogNumeric::ShowAndGetNumber(strChannel, g_localizeStrings.Get(19000), autoCloseTime) || autoCloseTime)
- iChannelNumber = atoi(strChannel.c_str());
- }
-
- if (iChannelNumber > 0 && iChannelNumber != channel->ChannelNumber())
- {
- CPVRChannelGroupPtr selectedGroup = g_PVRManager.GetPlayingGroup(channel->IsRadio());
- CFileItemPtr channel = selectedGroup->GetByChannelNumber(iChannelNumber);
- if (!channel || !channel->HasPVRChannelInfoTag())
- return false;
+ {
+ int iChannelNumber = atoi(strChannel.c_str());
+ if (iChannelNumber > 0 && iChannelNumber != playingChannel->ChannelNumber())
+ {
+ CPVRChannelGroupPtr selectedGroup = g_PVRManager.GetPlayingGroup(playingChannel->IsRadio());
+ CFileItemPtr channel = selectedGroup->GetByChannelNumber(iChannelNumber);
+ if (!channel || !channel->HasPVRChannelInfoTag())
+ return false;
- g_application.OnAction(CAction(ACTION_CHANNEL_SWITCH, (float)iChannelNumber));
+ g_application.OnAction(CAction(ACTION_CHANNEL_SWITCH, (float)iChannelNumber));
+ }
+ }
}
}
else
diff --git a/xbmc/video/windows/GUIWindowVideoNav.cpp b/xbmc/video/windows/GUIWindowVideoNav.cpp
index 10bd22a52d..37e01d9cf9 100644
--- a/xbmc/video/windows/GUIWindowVideoNav.cpp
+++ b/xbmc/video/windows/GUIWindowVideoNav.cpp
@@ -600,7 +600,6 @@ void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& it
CStdString strGenre = g_localizeStrings.Get(515); // Genre
CStdString strActor = g_localizeStrings.Get(20337); // Actor
CStdString strDirector = g_localizeStrings.Get(20339); // Director
- CStdString strMovie = g_localizeStrings.Get(20338); // Movie
//get matching names
m_database.GetMoviesByName(strSearch, tempItems);
@@ -653,7 +652,7 @@ void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& it
AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
m_database.GetMoviesByPlot(strSearch, tempItems);
- AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
+ AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20323) + "] ", items);
}
void CGUIWindowVideoNav::PlayItem(int iItem)