Merge pull request #3540 from Memphiz/libsdl
authordavilla <davilla@xbmc.org>
Fri, 1 Nov 2013 20:34:45 +0000 (13:34 -0700)
committerdavilla <davilla@xbmc.org>
Fri, 1 Nov 2013 20:34:45 +0000 (13:34 -0700)
[depends] - bump libsdl-native and libsdl (target) to 1.2.15 and add the...

47 files changed:
addons/skin.confluence/720p/DialogSelect.xml
addons/skin.confluence/720p/VideoFullScreen.xml
addons/skin.confluence/720p/script-XBMC_Lyrics-main.xml
addons/skin.confluence/media/flagging/AudioLang.png [new file with mode: 0644]
addons/skin.confluence/media/flagging/SubLang.png [new file with mode: 0644]
addons/xbmc.json/addon.xml
project/BuildDependencies/DownloadBuildDeps.bat
project/BuildDependencies/scripts/get_formed.cmd
system/keymaps/joystick.xml [new file with mode: 0644]
system/settings/rbp.xml
system/settings/settings.xml
xbmc/GUIInfoManager.cpp
xbmc/GUIInfoManager.h
xbmc/GUILargeTextureManager.cpp
xbmc/GUILargeTextureManager.h
xbmc/TextureCacheJob.cpp
xbmc/cores/dvdplayer/DVDPlayer.cpp
xbmc/cores/omxplayer/Makefile.in
xbmc/cores/omxplayer/OMXAudio.cpp
xbmc/cores/omxplayer/OMXAudio.h
xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
xbmc/cores/omxplayer/OMXAudioCodecOMX.h
xbmc/cores/omxplayer/OMXImage.cpp
xbmc/cores/omxplayer/OMXImage.h
xbmc/cores/omxplayer/OMXPlayerAudio.cpp
xbmc/cores/omxplayer/PCMRemap.cpp [new file with mode: 0644]
xbmc/cores/omxplayer/PCMRemap.h [new file with mode: 0644]
xbmc/epg/EpgInfoTag.cpp
xbmc/epg/EpgSearchFilter.cpp
xbmc/epg/EpgSearchFilter.h
xbmc/guilib/GUIImage.cpp
xbmc/guilib/GUIImage.h
xbmc/guilib/GUITexture.cpp
xbmc/guilib/GUITexture.h
xbmc/input/ButtonTranslator.cpp
xbmc/interfaces/json-rpc/FileItemHandler.cpp
xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
xbmc/interfaces/json-rpc/PVROperations.cpp
xbmc/interfaces/json-rpc/PVROperations.h
xbmc/interfaces/json-rpc/ServiceDescription.h
xbmc/interfaces/json-rpc/methods.json
xbmc/interfaces/json-rpc/types.json
xbmc/interfaces/legacy/Control.cpp
xbmc/interfaces/legacy/Control.h
xbmc/settings/SettingControl.cpp
xbmc/settings/SettingControl.h
xbmc/settings/windows/GUIControlSettings.cpp

index 195e474..62f6d4f 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <window type="dialog">
+       <zorder>1</zorder>
        <defaultcontrol always="true">3</defaultcontrol>
        <coordinates>
                <system>1</system>
index 1cc784d..38911f6 100644 (file)
                                        <itemgap>5</itemgap>
                                        <orientation>horizontal</orientation>
                                        <control type="label" id="1">
-                                               <width min="10" max="710">auto</width>
+                                               <width min="10" max="520">auto</width>
                                                <height>30</height>
                                                <font>font30</font>
                                                <align>left</align>
                                                <aspectratio align="center">keep</aspectratio>
                                                <texture>$INFO[VideoPlayer.AudioChannels,flagging/audio/,.png]</texture>
                                        </control>
+                                       <control type="group" id="1">
+                                               <width>85</width>
+                                               <height>35</height>
+                                               <visible>!IsEmpty(VideoPlayer.AudioLanguage)</visible>
+                                               <control type="image" id="1">
+                                                       <posx>5</posx>
+                                                       <posy>0</posy>
+                                                       <description>Audio Language Image</description>
+                                                       <width>80</width>
+                                                       <height>35</height>
+                                                       <texture>flagging/AudioLang.png</texture>
+                                               </control>
+                                               <control type="label" id="1">
+                                                       <posx>38</posx>
+                                                       <posy>2</posy>
+                                                       <width>47</width>
+                                                       <height>35</height>
+                                                       <font>font13</font>
+                                                       <align>left</align>
+                                                       <label>$INFO[VideoPlayer.AudioLanguage]</label>
+                                                       <textcolor>grey</textcolor>
+                                               </control>
+                                       </control>
+                                       <control type="group" id="1">
+                                               <width>85</width>
+                                               <height>35</height>
+                                               <visible>!IsEmpty(VideoPlayer.SubtitlesLanguage)</visible>
+                                               <control type="image" id="1">
+                                                       <posx>5</posx>
+                                                       <posy>0</posy>
+                                                       <width>80</width>
+                                                       <height>35</height>
+                                                       <texture>flagging/SubLang.png</texture>
+                                               </control>
+                                               <control type="label" id="1">
+                                                       <posx>38</posx>
+                                                       <posy>2</posy>
+                                                       <width>47</width>
+                                                       <height>35</height>
+                                                       <font>font13</font>
+                                                       <align>left</align>
+                                                       <label>$INFO[VideoPlayer.SubtitlesLanguage]</label>
+                                                       <textcolor>grey</textcolor>
+                                               </control>
+                                       </control>
                                </control>
                                <control type="label" id="1">
                                        <posx>0</posx>
index e73326d..9af3b01 100644 (file)
@@ -45,7 +45,7 @@
                                <width>550</width>
                                <height>30</height>
                                <font>font30_title</font>
-                               <label>$ADDON[script.cu.lrclyrics 0]</label>
+                               <label>$ADDON[script.cu.lrclyrics 32199]</label>
                                <align>right</align>
                                <aligny>center</aligny>
                                <textcolor>white</textcolor>
diff --git a/addons/skin.confluence/media/flagging/AudioLang.png b/addons/skin.confluence/media/flagging/AudioLang.png
new file mode 100644 (file)
index 0000000..fdbe5ae
Binary files /dev/null and b/addons/skin.confluence/media/flagging/AudioLang.png differ
diff --git a/addons/skin.confluence/media/flagging/SubLang.png b/addons/skin.confluence/media/flagging/SubLang.png
new file mode 100644 (file)
index 0000000..9952aed
Binary files /dev/null and b/addons/skin.confluence/media/flagging/SubLang.png differ
index 5fb5c72..b209d7a 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<addon id="xbmc.json" version="6.6.0" provider-name="Team XBMC">
+<addon id="xbmc.json" version="6.7.0" provider-name="Team XBMC">
   <backwards-compatibility abi="6.0.0"/>
   <requires>
     <import addon="xbmc.core" version="0.1.0"/>
index fdc51e4..ed76ec7 100644 (file)
@@ -33,10 +33,15 @@ FOR /F "tokens=*" %%S IN ('dir /B "*_d.bat"') DO (
   CALL %%S
 )
 
+SET FORMED_OK_FLAG=%TMP_PATH%\got-all-formed-packages
 REM Trick to preserve console title
 start /b /wait cmd.exe /c get_formed.cmd
-IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL%
+IF NOT EXIST %FORMED_OK_FLAG% (
+  ECHO ERROR: Not all formed packages are ready!
+  EXIT /B 101
+)
 
 cd %CUR_PATH%
 
 rmdir %TMP_PATH% /S /Q
+EXIT /B 0
index d5a0707..a3f630f 100644 (file)
@@ -9,6 +9,11 @@ ECHO Aborting...
 EXIT /B 20
 )
 
+REM Clear succeed flag
+IF EXIST %FORMED_OK_FLAG% (
+  del /F /Q "%FORMED_OK_FLAG%" || EXIT /B 4
+)
+
 CALL :setStageName Starting downloads of formed packages...
 SET SCRIPT_PATH=%CD%
 CD %DL_PATH% || EXIT /B 10
@@ -18,6 +23,7 @@ IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL%
 )
 
 CALL :setStageName All formed packages ready.
+ECHO %DATE% %TIME% > "%FORMED_OK_FLAG%"
 EXIT /B 0
 REM End of main body
 
diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml
new file mode 100644 (file)
index 0000000..197ed8a
--- /dev/null
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Button Mappings :                         -->
+<!--                                           -->
+<!-- ID              Button                    -->
+<!--                                           -->
+<!-- 1               A                         -->
+<!-- 2               B                         -->
+<!-- 3               X                         -->
+<!-- 4               Y                         -->
+<!-- 5               Left Shoulder             -->
+<!-- 6               Right Shoulder            -->
+<!-- 7               Back                      -->
+<!-- 8               Start                     -->
+<!-- 9               Left Stick Button         -->
+<!-- 10              Right Stick Button        -->
+<!-- 11              D-Pad Up                  -->
+<!-- 12              D-Pad Down                -->
+<!-- 13              D-Pad Left                -->
+<!-- 14              D-Pad Right               -->
+<!-- 15              Back                      -->
+
+<!-- Axis Mappings:                   -->
+<!--                                  -->
+<!-- ID              Button           -->
+<!--                                  -->
+<!-- 1               Left Stick L/R   -->
+<!-- 2               Left Stick U/D   -->
+<!-- 3 limit +1      Left Trigger     -->
+<!-- 3 limit -1      Right Trigger    -->
+<!-- 4               Right Stick L/R  -->
+<!-- 5               Right Stick U/D  -->
+
+<keymap>
+  <global>
+    <joystick>
+      <!-- A selects. B goes back. X gets context menu. Y goes fullscreen and back. -->
+      <button id="1">Select</button>
+      <button id="2">Back</button>
+      <button id="3">ContextMenu</button>
+      <button id="4">FullScreen</button>
+      <!--Left Shoulder Queues videos. Right shoulder displays the current queue. -->
+      <button id="5">Queue</button>
+      <button id="6">Playlist</button>
+      <button id="7">PreviousMenu</button>
+      <button id="8">XBMC.ActivateWindow(Home)</button>
+      <!-- Left stick click activates the shutdown menu. -->
+      <button id="9">XBMC.ActivateWindow(ShutdownMenu)</button>
+      <button id="10">XBMC.ActivateWindow(PlayerControls)</button>
+      <button id="11">Up</button>
+      <button id="12">Down</button>
+      <button id="13">Left</button>
+      <button id="14">Right</button>
+      <button id="15">PreviousMenu</button>
+      <axis id="1" limit="-1">Up</axis>
+      <axis id="1" limit="+1">Down</axis>
+      <axis id="2" limit="-1">Left</axis>
+      <axis id="2" limit="+1">Right</axis>
+      <axis id="3" limit="+1">ScrollUp</axis>
+      <axis id="3" limit="-1">ScrollDown</axis>
+      <!-- Push up on the right stick for volueme up. Push down for volume down. -->
+      <axis id="5" limit="-1">VolumeUp</axis>
+      <axis id="5" limit="+1">VolumeDown</axis>
+      <axis id="4" limit="-1">VolumeDown</axis>
+      <axis id="4" limit="+1">VolumeUp</axis>
+      <hat id="1" position="up">Up</hat>
+      <hat id="1" position="down">Down</hat>
+      <hat id="1" position="left">Left</hat>
+      <hat id="1" position="right">Right</hat>
+    </joystick>
+  </global>
+  <Home>
+    <joystick>
+      <button id="8">XBMC.Skin.ToggleSetting(HomeViewToggle)</button>
+    </joystick>
+  </Home>
+  <MyFiles>
+    <joystick>
+      <button id="6">Highlight</button>
+    </joystick>
+  </MyFiles>
+  <MyMusicPlaylist>
+    <joystick>
+      <button id="5">Delete</button>
+    </joystick>
+  </MyMusicPlaylist>
+  <MyMusicFiles>
+  </MyMusicFiles>
+  <MyMusicLibrary>
+  </MyMusicLibrary>
+  <FullscreenVideo>
+    <joystick>
+      <!--
+            A pauses and starts the video.
+            B stops the video.
+            X opens the onscreen display.
+            Y switches in and out of full screen
+            -->
+      <button id="1">Pause</button>
+      <button id="2">Stop</button>
+      <button id="3">OSD</button>
+      <!--
+            Left shoulder changes aspect ratio.
+            Right shoulder changes subtitles.
+            Right stick changes Audio Language.
+            Start button displays info.
+            -->
+      <button id="5">AspectRatio</button>
+      <button id="6">ShowSubtitles</button>
+      <button id="7">SmallStepBack</button>
+      <button id="8">Info</button>
+      <button id="10">AudioNextLanguage</button>
+      <button id="11">BigStepForward</button>
+      <button id="12">BigStepBack</button>
+      <button id="13">StepBack</button>
+      <button id="14">StepForward</button>
+      <!-- D-pad does what you'd expect. Triggers fast forward and rewind. Left stick scans forward and back. -->
+      <axis id="3" limit="+1">AnalogRewind</axis>
+      <axis id="3" limit="-1">AnalogFastForward</axis>
+      <hat id="1" position="up">BigStepForward</hat>
+      <hat id="1" position="down">BigStepBack</hat>
+      <hat id="1" position="left">StepBack</hat>
+      <hat id="1" position="right">StepForward</hat>
+    </joystick>
+  </FullscreenVideo>
+  <FullscreenLiveTV>
+    <joystick>
+      <button id="11">ChannelUp</button>
+      <button id="12">ChannelDown</button>
+      <button id="13">PreviousChannelGroup</button>
+      <button id="14">NextChannelGroup</button>
+      <hat id="1" position="up">ChannelUp</hat>
+      <hat id="1" position="down">ChannelDown</hat>
+      <hat id="1" position="left">PreviousChannelGroup</hat>
+      <hat id="1" position="right">NextChannelGroup</hat>
+    </joystick>
+  </FullscreenLiveTV>
+  <FullscreenInfo>
+    <joystick>
+      <button id="2">Close</button>
+      <button id="3">OSD</button>
+      <button id="8">Close</button>
+      <axis id="3" limit="+1">AnalogRewind</axis>
+      <axis id="3" limit="-1">AnalogFastForward</axis>
+    </joystick>
+  </FullscreenInfo>
+  <PlayerControls>
+    <joystick>
+      <button id="3">Close</button>
+      <button id="9">Close</button>
+      <button id="10">Close</button>
+    </joystick>
+  </PlayerControls>
+  <Visualisation>
+    <joystick>
+      <button id="1">Pause</button>
+      <button id="2">Stop</button>
+      <button id="3">XBMC.ActivateWindow(MusicOSD)</button>
+      <button id="5">XBMC.ActivateWindow(VisualisationPresetList)</button>
+      <button id="6">Info</button>
+      <button id="10">XBMC.ActivateWindow(MusicOSD)</button>
+      <button id="11">SkipNext</button>
+      <button id="12">SkipPrevious</button>
+      <button id="13">PreviousPreset</button>
+      <button id="14">NextPreset</button>
+      <axis id="3" limit="+1">AnalogRewind</axis>
+      <axis id="3" limit="-1">AnalogFastForward</axis>
+      <hat id="1" position="up">SkipNext</hat>
+      <hat id="1" position="down">SkipPrevious</hat>
+      <hat id="1" position="left">PreviousPreset</hat>
+      <hat id="1" position="right">NextPreset</hat>
+    </joystick>
+  </Visualisation>
+  <MusicOSD>
+    <joystick>
+      <button id="3">Close</button>
+      <button id="6">Info</button>
+    </joystick>
+  </MusicOSD>
+  <VisualisationSettings>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </VisualisationSettings>
+  <VisualisationPresetList>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </VisualisationPresetList>
+  <SlideShow>
+    <joystick>
+      <button id="1">Pause</button>
+      <button id="2">Stop</button>
+      <button id="4">ZoomNormal</button>
+      <button id="5">Rotate</button>
+      <button id="6">CodecInfo</button>
+      <button id="11">ZoomIn</button>
+      <button id="12">ZoomOut</button>
+      <button id="13">PreviousPicture</button>
+      <button id="14">NextPicture</button>
+      <axis id="1">AnalogMove</axis>
+      <axis id="2">AnalogMove</axis>
+      <axis id="3" limit="+1">ZoomOut</axis>
+      <axis id="3" limit="-1">ZoomIn</axis>
+      <hat id="1" position="up">ZoomIn</hat>
+      <hat id="1" position="down">ZoomOut</hat>
+      <hat id="1" position="left">PreviousPicture</hat>
+      <hat id="1" position="right">NextPicture</hat>
+    </joystick>
+  </SlideShow>
+  <ScreenCalibration>
+    <joystick>
+      <button id="3">ResetCalibration</button>
+      <button id="5">NextResolution</button>
+      <button id="6">NextCalibration</button>
+    </joystick>
+  </ScreenCalibration>
+  <GUICalibration>
+    <joystick>
+      <button id="3">ResetCalibration</button>
+      <button id="5">NextResolution</button>
+      <button id="6">NextCalibration</button>
+    </joystick>
+  </GUICalibration>
+  <VideoOSD>
+    <joystick>
+      <button id="3">Close</button>
+    </joystick>
+  </VideoOSD>
+  <VideoMenu>
+    <joystick>
+      <button id="2">Stop</button>
+      <button id="3">OSD</button>
+      <button id="5">AspectRatio</button>
+      <button id="8">Info</button>
+    </joystick>
+  </VideoMenu>
+  <OSDVideoSettings>
+    <joystick>
+      <button id="5">AspectRatio</button>
+      <button id="3">Close</button>
+    </joystick>
+  </OSDVideoSettings>
+  <OSDAudioSettings>
+    <joystick>
+      <button id="5">AspectRatio</button>
+      <button id="3">Close</button>
+    </joystick>
+  </OSDAudioSettings>
+  <VideoBookmarks>
+    <joystick>
+      <button id="5">Delete</button>
+    </joystick>
+  </VideoBookmarks>
+  <MyVideoLibrary>
+  </MyVideoLibrary>
+  <MyVideoFiles>
+  </MyVideoFiles>
+  <MyVideoPlaylist>
+    <joystick>
+      <button id="5">Delete</button>
+    </joystick>
+  </MyVideoPlaylist>
+  <VirtualKeyboard>
+    <joystick>
+      <button id="2">BackSpace</button>
+      <button id="4">Symbols</button>
+      <button id="5">Shift</button>
+      <button id="9">Enter</button>
+      <axis id="3" limit="+1">CursorLeft</axis>
+      <axis id="3" limit="-1">CursorRight</axis>
+    </joystick>
+  </VirtualKeyboard>
+  <ContextMenu>
+    <joystick>
+      <button id="2">Close</button>
+      <button id="3">Close</button>
+    </joystick>
+  </ContextMenu>
+  <Scripts>
+    <joystick>
+      <button id="3">Info</button>
+    </joystick>
+  </Scripts>
+  <Settings>
+    <joystick>
+      <button id="2">PreviousMenu</button>
+    </joystick>
+  </Settings>
+  <AddonInformation>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </AddonInformation>
+  <AddonSettings>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </AddonSettings>
+  <TextViewer>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </TextViewer>
+  <shutdownmenu>
+    <joystick>
+      <button id="2">PreviousMenu</button>
+      <button id="9">PreviousMenu</button>
+    </joystick>
+  </shutdownmenu>
+  <submenu>
+    <joystick>
+      <button id="2">PreviousMenu</button>
+    </joystick>
+  </submenu>
+  <MusicInformation>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </MusicInformation>
+  <MovieInformation>
+    <joystick>
+      <button id="2">Close</button>
+    </joystick>
+  </MovieInformation>
+  <NumericInput>
+    <joystick>
+      <button id="2">BackSpace</button>
+      <button id="9">Enter</button>
+    </joystick>
+  </NumericInput>
+  <GamepadInput>
+    <joystick>
+      <button id="9">Stop</button>
+    </joystick>
+  </GamepadInput>
+  <LockSettings>
+    <joystick>
+      <button id="2">PreviousMenu</button>
+      <button id="9">Close</button>
+    </joystick>
+  </LockSettings>
+  <ProfileSettings>
+    <joystick>
+      <button id="2">PreviousMenu</button>
+      <button id="9">Close</button>
+    </joystick>
+  </ProfileSettings>
+</keymap>
index 166314a..63a00b7 100644 (file)
@@ -60,9 +60,6 @@
         <setting id="audiooutput.stereoupmix">
           <visible>false</visible>
         </setting>
-        <setting id="audiooutput.channels">
-          <visible>false</visible>
-        </setting>
         <setting id="audiooutput.streamsilence">
           <level>2</level>
           <default>0</default>
index d25dd72..a6bed23 100644 (file)
           <dependencies>
             <dependency type="enable" setting="lookandfeel.enablerssfeeds">true</dependency>
           </dependencies>
-          <control type="button" format="action" />
+          <control type="button" format="action" attributes="hide_value" />
         </setting>
       </group>
     </category>
         <setting id="masterlock.lockcode" type="string" label="20100" help="36396">
           <level>2</level>
           <default>-</default>
-          <control type="button" format="action" />
+          <control type="button" format="action" attributes="hide_value"/>
         </setting>
         <setting id="masterlock.startuplock" type="boolean" label="20076" help="36397">
           <level>2</level>
index 16c2050..8a0abbe 100644 (file)
@@ -382,6 +382,7 @@ const infomap videoplayer[] =    {{ "title",            VIDEOPLAYER_TITLE },
                                   { "videoaspect",      VIDEOPLAYER_VIDEO_ASPECT },
                                   { "audiocodec",       VIDEOPLAYER_AUDIO_CODEC },
                                   { "audiochannels",    VIDEOPLAYER_AUDIO_CHANNELS },
+                                  { "audiolanguage",    VIDEOPLAYER_AUDIO_LANG },
                                   { "hasteletext",      VIDEOPLAYER_HASTELETEXT },
                                   { "lastplayed",       VIDEOPLAYER_LASTPLAYED },
                                   { "playcount",        VIDEOPLAYER_PLAYCOUNT },
@@ -1560,6 +1561,14 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow, CStdString *fa
       strLabel.Format("%i", m_audioInfo.channels);
     }
     break;
+  case VIDEOPLAYER_AUDIO_LANG:
+    if(g_application.m_pPlayer->IsPlaying())
+    {
+      SPlayerAudioStreamInfo info;
+      g_application.m_pPlayer->GetAudioStreamInfo(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream, info);
+      strLabel = info.language;
+    }
+    break;
   case VIDEOPLAYER_STEREOSCOPIC_MODE:
     if(g_application.m_pPlayer->IsPlaying())
     {
index 14ae761..e9bbb4d 100644 (file)
@@ -277,6 +277,7 @@ namespace INFO
 #define VIDEOPLAYER_IS_STEREOSCOPIC   310
 #define VIDEOPLAYER_STEREOSCOPIC_MODE 311
 #define VIDEOPLAYER_SUBTITLES_LANG    312
+#define VIDEOPLAYER_AUDIO_LANG        313
 
 #define CONTAINER_CAN_FILTER         342
 #define CONTAINER_CAN_FILTERADVANCED 343
index c3ada3d..45fa8aa 100644 (file)
 using namespace std;
 
 
-CImageLoader::CImageLoader(const CStdString &path)
+CImageLoader::CImageLoader(const CStdString &path, const bool useCache)
 {
   m_path = path;
   m_texture = NULL;
+  m_use_cache = useCache;
 }
 
 CImageLoader::~CImageLoader()
@@ -46,18 +47,22 @@ CImageLoader::~CImageLoader()
 bool CImageLoader::DoWork()
 {
   bool needsChecking = false;
+  CStdString loadPath;
 
   CStdString texturePath = g_TextureManager.GetTexturePath(m_path);
-  CStdString loadPath = CTextureCache::Get().CheckCachedImage(texturePath, true, needsChecking); 
+  if (m_use_cache)
+    loadPath = CTextureCache::Get().CheckCachedImage(texturePath, true, needsChecking);
+  else
+    loadPath = texturePath;
 
-  if (loadPath.IsEmpty())
+  if (m_use_cache && loadPath.IsEmpty())
   {
     // not in our texture cache, so try and load directly and then cache the result
     loadPath = CTextureCache::Get().CacheImage(texturePath, &m_texture);
     if (m_texture)
       return true; // we're done
   }
-  if (!loadPath.IsEmpty())
+  if (!m_use_cache || !loadPath.IsEmpty())
   {
     // direct route - load the image
     unsigned int start = XbmcThreads::SystemClockMillis();
@@ -148,7 +153,7 @@ void CGUILargeTextureManager::CleanupUnusedImages(bool immediately)
 
 // if available, increment reference count, and return the image.
 // else, add to the queue list if appropriate.
-bool CGUILargeTextureManager::GetImage(const CStdString &path, CTextureArray &texture, bool firstRequest)
+bool CGUILargeTextureManager::GetImage(const CStdString &path, CTextureArray &texture, bool firstRequest, const bool useCache)
 {
   CSingleLock lock(m_listSection);
   for (listIterator it = m_allocated.begin(); it != m_allocated.end(); ++it)
@@ -164,7 +169,7 @@ bool CGUILargeTextureManager::GetImage(const CStdString &path, CTextureArray &te
   }
 
   if (firstRequest)
-    QueueImage(path);
+    QueueImage(path, useCache);
 
   return true;
 }
@@ -197,7 +202,7 @@ void CGUILargeTextureManager::ReleaseImage(const CStdString &path, bool immediat
 }
 
 // queue the image, and start the background loader if necessary
-void CGUILargeTextureManager::QueueImage(const CStdString &path)
+void CGUILargeTextureManager::QueueImage(const CStdString &path, bool useCache)
 {
   CSingleLock lock(m_listSection);
   for (queueIterator it = m_queued.begin(); it != m_queued.end(); ++it)
@@ -212,7 +217,7 @@ void CGUILargeTextureManager::QueueImage(const CStdString &path)
 
   // queue the item
   CLargeTexture *image = new CLargeTexture(path);
-  unsigned int jobID = CJobManager::GetInstance().AddJob(new CImageLoader(path), this, CJob::PRIORITY_NORMAL);
+  unsigned int jobID = CJobManager::GetInstance().AddJob(new CImageLoader(path, useCache), this, CJob::PRIORITY_NORMAL);
   m_queued.push_back(make_pair(jobID, image));
 }
 
index 080c11b..4bc957a 100644 (file)
@@ -35,7 +35,7 @@
 class CImageLoader : public CJob
 {
 public:
-  CImageLoader(const CStdString &path);
+  CImageLoader(const CStdString &path, const bool useCache);
   virtual ~CImageLoader();
 
   /*!
@@ -43,6 +43,7 @@ public:
    */
   virtual bool DoWork();
 
+  bool          m_use_cache; ///< Whether or not to use any caching with this image
   CStdString    m_path; ///< path of image to load
   CBaseTexture *m_texture; ///< Texture object to load the image into \sa CBaseTexture.
 };
@@ -85,7 +86,7 @@ public:
    \return true if the image exists, else false.
    \sa CGUITextureArray and CGUITexture
    */
-  bool GetImage(const CStdString &path, CTextureArray &texture, bool firstRequest);
+  bool GetImage(const CStdString &path, CTextureArray &texture, bool firstRequest, bool useCache = true);
 
   /*!
    \brief Request a texture to be unloaded.
@@ -135,7 +136,7 @@ private:
     unsigned int m_timeToDelete;
   };
 
-  void QueueImage(const CStdString &path);
+  void QueueImage(const CStdString &path, bool useCache = true);
 
   std::vector< std::pair<unsigned int, CLargeTexture *> > m_queued;
   std::vector<CLargeTexture *> m_allocated;
index 97855f7..0d53f4a 100644 (file)
@@ -33,6 +33,9 @@
 #include "FileItem.h"
 #include "music/MusicThumbLoader.h"
 #include "music/tags/MusicInfoTag.h"
+#if defined(HAS_OMXPLAYER)
+#include "cores/omxplayer/OMXImage.h"
+#endif
 
 CTextureCacheJob::CTextureCacheJob(const CStdString &url, const CStdString &oldHash)
 {
@@ -87,6 +90,18 @@ bool CTextureCacheJob::CacheTexture(CBaseTexture **out_texture)
   else if (m_details.hash == m_oldHash)
     return true;
 
+#if defined(HAS_OMXPLAYER)
+  if (COMXImage::CreateThumb(image, width, height, additional_info, CTextureCache::GetCachedPath(m_cachePath + ".jpg")))
+  {
+    m_details.width = width;
+    m_details.height = height;
+    m_details.file = m_cachePath + ".jpg";
+    if (out_texture)
+      *out_texture = LoadImage(CTextureCache::GetCachedPath(m_details.file), width, height, additional_info);
+    CLog::Log(LOGDEBUG, "Fast %s image '%s' to '%s': %p", m_oldHash.IsEmpty() ? "Caching" : "Recaching", image.c_str(), m_details.file.c_str(), out_texture);
+    return true;
+  }
+#endif
   CBaseTexture *texture = LoadImage(image, width, height, additional_info);
   if (texture)
   {
index c412b9f..6751cdd 100644 (file)
@@ -2751,6 +2751,7 @@ int CDVDPlayer::GetAudioStream()
 
 void CDVDPlayer::SetAudioStream(int iStream)
 {
+  CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = iStream;
   m_messenger.Put(new CDVDMsgPlayerSetAudioStream(iStream));
   SynchronizeDemuxer(100);
 }
@@ -2871,7 +2872,7 @@ bool CDVDPlayer::OpenAudioStream(int iStream, int source, bool reset)
 
   /* audio normally won't consume full cpu, so let it have prio */
   m_dvdPlayerAudio.SetPriority(GetPriority()+1);
-
+  CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream =  m_SelectionStreams.IndexOf(STREAM_AUDIO, source, iStream);
   return true;
 }
 
index e5cad70..3163282 100644 (file)
@@ -7,6 +7,7 @@ SRCS += OMXAudioCodecOMX.cpp
 SRCS += OMXPlayerAudio.cpp
 SRCS += OMXPlayerVideo.cpp
 SRCS += OMXImage.cpp
+SRCS += PCMRemap.cpp
 
 LIB = omxplayer.a
 
index 764f26a..a03d53b 100644 (file)
 
 using namespace std;
 
-#define OMX_MAX_CHANNELS 10
-
-static enum AEChannel OMXChannelMap[OMX_MAX_CHANNELS] = 
-{
-  AE_CH_FL      , AE_CH_FR, 
-  AE_CH_FC      , AE_CH_LFE, 
-  AE_CH_BL      , AE_CH_BR,
-  AE_CH_SL      , AE_CH_SR,
-  AE_CH_BC      , AE_CH_RAW
-};
-
-static enum OMX_AUDIO_CHANNELTYPE OMXChannels[OMX_MAX_CHANNELS] =
-{
-  OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF,
-  OMX_AUDIO_ChannelCF, OMX_AUDIO_ChannelLFE,
-  OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR,
-  OMX_AUDIO_ChannelLS, OMX_AUDIO_ChannelRS,
-  OMX_AUDIO_ChannelCS, OMX_AUDIO_ChannelNone
-};
-
-static unsigned int WAVEChannels[OMX_MAX_CHANNELS] =
-{
-  SPEAKER_FRONT_LEFT,       SPEAKER_FRONT_RIGHT,
-  SPEAKER_TOP_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
-  SPEAKER_BACK_LEFT,        SPEAKER_BACK_RIGHT,
-  SPEAKER_SIDE_LEFT,        SPEAKER_SIDE_RIGHT,
-  SPEAKER_BACK_CENTER,      0
-};
-
 static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
 static const uint16_t AC3FSCod   [] = {48000, 44100, 32000, 0};
 
 static const uint16_t DTSFSCod   [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0};
 
-// 7.1 downmixing coefficients
-const float downmixing_coefficients_8[OMX_AUDIO_MAXCHANNELS] = {
-  //        L       R
-  /* L */   1,      0,
-  /* R */   0,      1,
-  /* C */   0.7071, 0.7071,
-  /* LFE */ 0.7071, 0.7071,
-  /* Ls */  0.7071, 0,
-  /* Rs */  0,      0.7071,
-  /* Lr */  0.7071, 0,
-  /* Rr */  0,      0.7071
-};
-
-// 7.1 downmixing coefficients with boosted centre channel
-const float downmixing_coefficients_8_boostcentre[OMX_AUDIO_MAXCHANNELS] = {
-  //        L       R
-  /* L */   0.7071, 0,
-  /* R */   0,      0.7071,
-  /* C */   1,      1,
-  /* LFE */ 0.7071, 0.7071,
-  /* Ls */  0.7071, 0,
-  /* Rs */  0,      0.7071,
-  /* Lr */  0.7071, 0,
-  /* Rr */  0,      0.7071
-};
-
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
@@ -118,11 +63,13 @@ COMXAudio::COMXAudio() :
   m_BytesPerSec     (0      ),
   m_BufferLen       (0      ),
   m_ChunkLen        (0      ),
+  m_InputChannels   (0      ),
+  m_OutputChannels  (0      ),
   m_BitsPerSample   (0      ),
   m_maxLevel        (0.0f   ),
   m_amplification   (1.0f   ),
   m_attenuation     (1.0f   ),
-  m_desired_attenuation(1.0f),
+  m_submitted       (0.0f   ),
   m_omx_clock       (NULL   ),
   m_av_clock        (NULL   ),
   m_settings_changed(false  ),
@@ -149,41 +96,6 @@ COMXAudio::~COMXAudio()
   _aligned_free(m_vizBuffer);
 }
 
-
-CAEChannelInfo COMXAudio::GetChannelLayout(AEAudioFormat format)
-{
-  unsigned int count = 0;
-
-  if(format.m_dataFormat == AE_FMT_AC3 ||
-    format.m_dataFormat == AE_FMT_DTS ||
-    format.m_dataFormat == AE_FMT_EAC3)
-    count = 2;
-  else if (format.m_dataFormat == AE_FMT_TRUEHD ||
-    format.m_dataFormat == AE_FMT_DTSHD)
-    count = 8;
-  else
-  {
-    for (unsigned int c = 0; c < 8; ++c)
-    {
-      for (unsigned int i = 0; i < format.m_channelLayout.Count(); ++i)
-      {
-        if (format.m_channelLayout[i] == OMXChannelMap[c])
-        {
-          count = c + 1;
-          break;
-        }
-      }
-    }
-  }
-
-  CAEChannelInfo info;
-  for (unsigned int i = 0; i < count; ++i)
-    info += OMXChannelMap[i];
-
-  return info;
-}
-
-
 bool COMXAudio::PortSettingsChanged()
 {
   CSingleLock lock (m_critSection);
@@ -218,7 +130,7 @@ bool COMXAudio::PortSettingsChanged()
   }
 
   SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100));
-  ApplyVolume();
+  UpdateAttenuation();
 
   if( m_omx_mixer.IsInitialized() )
   {
@@ -232,10 +144,9 @@ bool COMXAudio::PortSettingsChanged()
       return false;
     }
 
-    /* mixer output is always stereo */
-    m_pcm_output.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
-    m_pcm_output.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
-    m_pcm_output.nChannels = 2;
+    memcpy(m_pcm_output.eChannelMapping, m_output_channels, sizeof(m_output_channels));
+    // round up to power of 2
+    m_pcm_output.nChannels = m_OutputChannels > 4 ? 8 : m_OutputChannels > 2 ? 4 : m_OutputChannels;
     /* limit samplerate (through resampling) if requested */
     m_pcm_output.nSamplingRate = std::min((int)m_pcm_output.nSamplingRate, CSettings::Get().GetInt("audiooutput.samplerate"));
 
@@ -489,7 +400,15 @@ bool COMXAudio::PortSettingsChanged()
   return true;
 }
 
-bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, bool bUsePassthrough, bool bUseHWDecode)
+static unsigned count_bits(int64_t value)
+{
+  unsigned bits = 0;
+  for(;value;++bits)
+    value &= value - 1;
+  return bits;
+}
+
+bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode)
 {
   CSingleLock lock (m_critSection);
   OMX_ERRORTYPE omx_err;
@@ -502,9 +421,11 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
   m_HWDecode    = bUseHWDecode;
   m_Passthrough = bUsePassthrough;
 
+  m_InputChannels = count_bits(channelMap);
   m_format = format;
+  enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
 
-  if(m_format.m_channelLayout.Count() == 0)
+  if(m_InputChannels == 0)
     return false;
 
   if(hints.samplerate == 0)
@@ -539,60 +460,44 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
   m_drc         = 0;
 
   memset(m_input_channels, 0x0, sizeof(m_input_channels));
+  memset(m_output_channels, 0x0, sizeof(m_output_channels));
   memset(&m_wave_header, 0x0, sizeof(m_wave_header));
 
-  for(int i = 0; i < OMX_AUDIO_MAXCHANNELS; i++)
-  {
-    m_pcm_input.eChannelMapping[i] = OMX_AUDIO_ChannelNone;
-    m_input_channels[i] = OMX_AUDIO_ChannelMax;
-  }
-
-  m_input_channels[0] = OMX_AUDIO_ChannelLF;
-  m_input_channels[1] = OMX_AUDIO_ChannelRF;
-  m_input_channels[2] = OMX_AUDIO_ChannelMax;
-
   m_wave_header.Format.nChannels  = 2;
   m_wave_header.dwChannelMask     = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
 
   if (!m_Passthrough)
   {
-    /* setup input channel map */
-    int map = 0;
-    int chan = 0;
-
-    for (unsigned int ch = 0; ch < m_format.m_channelLayout.Count(); ++ch)
-    {
-      for(map = 0; map < OMX_MAX_CHANNELS; ++map)
-      {
-        if (m_format.m_channelLayout[ch] == OMXChannelMap[map])
-        {
-          m_input_channels[chan] = OMXChannels[map]; 
-          m_wave_header.dwChannelMask |= WAVEChannels[map];
-          chan++;
-          break;
-        }
-      }
-    }
-
-    m_vizRemap.Initialize(m_format.m_channelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
+    enum PCMChannels inLayout[OMX_AUDIO_MAXCHANNELS];
+    enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
+    // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
+    if (channelMap == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) || channelMap == AV_CH_FRONT_CENTER)
+      layout = PCM_LAYOUT_2_0;
+    BuildChannelMap(inLayout, channelMap);
+    m_OutputChannels = BuildChannelMapCEA(outLayout, GetChannelLayout(layout));
+    CPCMRemap m_remap;
+    m_remap.Reset();
+    /*outLayout = */m_remap.SetInputFormat (m_InputChannels, inLayout, CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8, m_format.m_sampleRate);
+    m_remap.SetOutputFormat(m_OutputChannels, outLayout);
+    m_remap.GetDownmixMatrix(m_downmix_matrix);
+    m_wave_header.dwChannelMask = channelMap;
+    BuildChannelMapOMX(m_input_channels, channelMap);
+    BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout));
+
+    m_vizRemap.Initialize(GetAEChannelLayout(channelMap), CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
   }
 
-  OMX_INIT_STRUCTURE(m_pcm_input);
-
-  memcpy(m_pcm_input.eChannelMapping, m_input_channels, sizeof(m_input_channels));
-
   m_SampleRate    = m_format.m_sampleRate;
   m_BitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
-  m_BufferLen     = m_BytesPerSec = m_format.m_sampleRate * (16 >> 3) * m_format.m_channelLayout.Count();
+  m_BufferLen     = m_BytesPerSec = m_format.m_sampleRate * (16 >> 3) * m_InputChannels;
   m_BufferLen     *= AUDIO_BUFFER_SECONDS;
   // the audio_decode output buffer size is 32K, and typically we convert from
   // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the outbut buffer
   m_ChunkLen      = 48*1024;
 
   m_wave_header.Samples.wSamplesPerBlock    = 0;
-  m_wave_header.Format.nChannels            = m_format.m_channelLayout.Count();
-  m_wave_header.Format.nBlockAlign          = m_format.m_channelLayout.Count() * 
-    (m_BitsPerSample >> 3);
+  m_wave_header.Format.nChannels            = m_InputChannels;
+  m_wave_header.Format.nBlockAlign          = m_InputChannels * (m_BitsPerSample >> 3);
   // 0x8000 is custom format interpreted by GPU as WAVE_FORMAT_IEEE_FLOAT_PLANAR
   m_wave_header.Format.wFormatTag           = m_BitsPerSample == 32 ? 0x8000 : WAVE_FORMAT_PCM;
   m_wave_header.Format.nSamplesPerSec       = m_format.m_sampleRate;
@@ -602,12 +507,14 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
   m_wave_header.Format.cbSize               = 0;
   m_wave_header.SubFormat                   = KSDATAFORMAT_SUBTYPE_PCM;
 
+  OMX_INIT_STRUCTURE(m_pcm_input);
+  memcpy(m_pcm_input.eChannelMapping, m_input_channels, sizeof(m_input_channels));
   m_pcm_input.eNumData              = OMX_NumericalDataSigned;
   m_pcm_input.eEndian               = OMX_EndianLittle;
   m_pcm_input.bInterleaved          = OMX_TRUE;
   m_pcm_input.nBitPerSample         = m_BitsPerSample;
   m_pcm_input.ePCMMode              = OMX_AUDIO_PCMModeLinear;
-  m_pcm_input.nChannels             = m_format.m_channelLayout.Count();
+  m_pcm_input.nChannels             = m_InputChannels;
   m_pcm_input.nSamplingRate         = m_format.m_sampleRate;
 
   if(!m_omx_decoder.Initialize("OMX.broadcom.audio_decode", OMX_IndexParamAudioInit))
@@ -770,6 +677,8 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
   m_submitted_eos = false;
   m_failed_eos = false;
   m_last_pts      = DVD_NOPTS_VALUE;
+  m_submitted     = 0.0f;
+  m_maxLevel      = 0.0f;
 
   CLog::Log(LOGDEBUG, "COMXAudio::Initialize Input bps %d samplerate %d channels %d buffer size %d bytes per second %d",
       (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_BytesPerSec);
@@ -844,7 +753,12 @@ bool COMXAudio::Deinitialize()
 
   m_dllAvUtil.Unload();
 
+  while(!m_ampqueue.empty())
+    m_ampqueue.pop_front();
+
   m_last_pts      = DVD_NOPTS_VALUE;
+  m_submitted     = 0.0f;
+  m_maxLevel      = 0.0f;
 
   /* dummy call to inform PiAudioAE that audo is inactive */
   CAEFactory::FreeStream(0);
@@ -872,6 +786,8 @@ void COMXAudio::Flush()
     m_omx_render_hdmi.FlushAll();
 
   m_last_pts      = DVD_NOPTS_VALUE;
+  m_submitted     = 0.0f;
+  m_maxLevel      = 0.0f;
   m_LostSync      = true;
   m_setStartTime  = true;
 }
@@ -882,7 +798,7 @@ void COMXAudio::SetDynamicRangeCompression(long drc)
   CSingleLock lock (m_critSection);
   m_amplification = powf(10.0f, (float)drc / 2000.0f);
   if (m_settings_changed)
-    ApplyVolume();
+    UpdateAttenuation();
 }
 
 //***********************************************************************************************
@@ -891,7 +807,7 @@ void COMXAudio::SetMute(bool bMute)
   CSingleLock lock (m_critSection);
   m_Mute = bMute;
   if (m_settings_changed)
-    ApplyVolume();
+    UpdateAttenuation();
 }
 
 //***********************************************************************************************
@@ -900,7 +816,7 @@ void COMXAudio::SetVolume(float fVolume)
   CSingleLock lock (m_critSection);
   m_CurrentVolume = fVolume;
   if (m_settings_changed)
-    ApplyVolume();
+    UpdateAttenuation();
 }
 
 //***********************************************************************************************
@@ -915,46 +831,23 @@ bool COMXAudio::ApplyVolume(void)
 
   // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) (deprecated)
   double gain = pow(10, (g_advancedSettings.m_ac3Gain - 12.0f) / 20.0);
-  double r = 1.0;
-  const float* coeff = downmixing_coefficients_8;
 
-  // alternate coffeciciants that boost centre channel more
-  if(!CSettings::Get().GetBool("audiooutput.boostcentre") && m_format.m_channelLayout.Count() > 2)
-    coeff = downmixing_coefficients_8_boostcentre;
+  const float* coeff = m_downmix_matrix;
 
-  // normally we normalise the levels, can be skipped (boosted) at risk of distortion
-  if(!CSettings::Get().GetBool("audiooutput.normalizelevels"))
-  {
-    double sum_L = 0;
-    double sum_R = 0;
-    for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i)
-    {
-      if (m_input_channels[i] == OMX_AUDIO_ChannelMax)
-        break;
-      if(i & 1)
-        sum_R += coeff[i];
-      else
-        sum_L += coeff[i];
-    }
-
-    r /= max(sum_L, sum_R);
-  }
-  r *= gain;
-
-  OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix;
+  OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix;
   OMX_INIT_STRUCTURE(mix);
   OMX_ERRORTYPE omx_err;
 
-  assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16);
+  assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64);
 
   if (m_amplification != 1.0)
   {
     // reduce scaling so overflow can be seen
-    for(size_t i = 0; i < 16; ++i)
-      mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * 0.01f));
+    for(size_t i = 0; i < 8*8; ++i)
+      mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * gain * 0.01f));
 
     mix.nPortIndex = m_omx_decoder.GetInputPort();
-    omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix);
+    omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
     if(omx_err != OMX_ErrorNone)
     {
       CLog::Log(LOGERROR, "%s::%s - error setting decoder OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
@@ -962,11 +855,11 @@ bool COMXAudio::ApplyVolume(void)
       return false;
     }
   }
-  for(size_t i = 0; i < 16; ++i)
-    mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * fVolume * m_amplification * m_attenuation));
+  for(size_t i = 0; i < 8*8; ++i)
+    mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * gain * fVolume * m_amplification * m_attenuation));
 
   mix.nPortIndex = m_omx_mixer.GetInputPort();
-  omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix);
+  omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
   if(omx_err != OMX_ErrorNone)
   {
     CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
@@ -983,7 +876,7 @@ void COMXAudio::VizPacket(const void* data, unsigned int len, double pts)
     unsigned int vizBufferSamples = len / (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3);
 
     /* input frames */
-    unsigned int frames = vizBufferSamples / m_format.m_channelLayout.Count();
+    unsigned int frames = vizBufferSamples / m_InputChannels;
     float *floatBuffer = (float *)data;
 
     if (m_format.m_dataFormat != AE_FMT_FLOAT)
@@ -1005,7 +898,7 @@ void COMXAudio::VizPacket(const void* data, unsigned int len, double pts)
     m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames);
 
     /* output samples */
-    vizBufferSamples = vizBufferSamples / m_format.m_channelLayout.Count() * 2;
+    vizBufferSamples = vizBufferSamples / m_InputChannels * 2;
 
     /* viz size is limited */
     if(vizBufferSamples > VIS_PACKET_SIZE)
@@ -1067,7 +960,6 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
       return len;
   }
 
-  int m_InputChannels = m_format.m_channelLayout.Count();
   unsigned pitch = (m_Passthrough || m_HWDecode) ? 1:(m_BitsPerSample >> 3) * m_InputChannels;
   unsigned int demuxer_samples = len / pitch;
   unsigned int demuxer_samples_sent = 0;
@@ -1102,7 +994,7 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
        uint8_t *dst = omx_buffer->pBuffer;
        uint8_t *src = demuxer_content + demuxer_samples_sent * (m_BitsPerSample >> 3);
        // we need to extract samples from planar audio, so the copying needs to be done per plane
-       for (int i=0; i<m_InputChannels; i++)
+       for (int i=0; i<(int)m_InputChannels; i++)
        {
          memcpy(dst, src, omx_buffer->nFilledLen / m_InputChannels);
          dst += omx_buffer->nFilledLen / m_InputChannels;
@@ -1187,29 +1079,78 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
       }
     }
   }
-
+  m_submitted += (float)demuxer_samples / m_SampleRate;
   if (m_amplification != 1.0)
+    UpdateAttenuation();
+  return len;
+}
+
+void COMXAudio::UpdateAttenuation()
+{
+  if (m_amplification == 1.0)
   {
-    double level_pts = 0.0;
-    float level = GetMaxLevel(level_pts);
-    if (level_pts != 0.0)
-    {
-      float alpha_h = -1.0f/(0.025f*log10f(0.999f));
-      float alpha_r = -1.0f/(0.100f*log10f(0.900f));
-      float hold    = powf(10.0f, -1.0f / (alpha_h * g_advancedSettings.m_limiterHold));
-      float release = powf(10.0f, -1.0f / (alpha_r * g_advancedSettings.m_limiterRelease));
-      m_maxLevel = level > m_maxLevel ? level : hold * m_maxLevel + (1.0f-hold) * level;
+    ApplyVolume();
+    return;
+  }
 
-      float amp = m_amplification * m_desired_attenuation;
+  double level_pts = 0.0;
+  float level = GetMaxLevel(level_pts);
+  if (level_pts != 0.0)
+  {
+    amplitudes_t v;
+    v.level = level;
+    v.pts = level_pts;
+    m_ampqueue.push_back(v);
+  }
+  double stamp = m_av_clock->OMXMediaTime();
+  // discard too old data
+  while(!m_ampqueue.empty())
+  {
+    amplitudes_t &v = m_ampqueue.front();
+    /* we'll also consume if queue gets unexpectedly long to avoid filling memory */
+    if (v.pts == DVD_NOPTS_VALUE || v.pts < stamp || v.pts - stamp > DVD_SEC_TO_TIME(15.0))
+      m_ampqueue.pop_front();
+    else break;
+  }
+  float maxlevel = 0.0f, imminent_maxlevel = 0.0f;
+  for (int i=0; i < (int)m_ampqueue.size(); i++)
+  {
+    amplitudes_t &v = m_ampqueue[i];
+    maxlevel = std::max(maxlevel, v.level);
+    // check for maximum volume in next 200ms
+    if (v.pts != DVD_NOPTS_VALUE && v.pts < stamp + DVD_SEC_TO_TIME(0.2))
+      imminent_maxlevel = std::max(imminent_maxlevel, v.level);
+  }
 
-      // want m_maxLevel * amp -> 1.0
-      m_desired_attenuation = std::min(1.0f, std::max(m_desired_attenuation / (amp * m_maxLevel), 1.0f/m_amplification));
-      m_attenuation = release * m_attenuation + (1.0f-release) * m_desired_attenuation;
+  if (maxlevel != 0.0)
+  {
+    float alpha_h = -1.0f/(0.025f*log10f(0.999f));
+    float alpha_r = -1.0f/(0.100f*log10f(0.900f));
+    float decay  = powf(10.0f, -1.0f / (alpha_h * g_advancedSettings.m_limiterHold));
+    float attack = powf(10.0f, -1.0f / (alpha_r * g_advancedSettings.m_limiterRelease));
+    // if we are going to clip imminently then deal with it now
+    if (imminent_maxlevel > m_maxLevel)
+      m_maxLevel = imminent_maxlevel;
+    // clip but not imminently can ramp up more slowly
+    else if (maxlevel > m_maxLevel)
+      m_maxLevel = attack * m_maxLevel + (1.0f-attack) * maxlevel;
+    // not clipping, decay more slowly
+    else
+      m_maxLevel = decay  * m_maxLevel + (1.0f-decay ) * maxlevel;
 
-      ApplyVolume();
-    }
+    // want m_maxLevel * amp -> 1.0
+    float amp = m_amplification * m_attenuation;
+
+    // We fade in the attenuation over first couple of seconds
+    float start = std::min(std::max((m_submitted-1.0f), 0.0f), 1.0f);
+    float attenuation = std::min(1.0f, std::max(m_attenuation / (amp * m_maxLevel), 1.0f/m_amplification));
+    m_attenuation = (1.0f - start) * 1.0f/m_amplification + start * attenuation;
   }
-  return len;
+  else
+  {
+    m_attenuation = 1.0f/m_amplification;
+  }
+  ApplyVolume();
 }
 
 //***********************************************************************************************
@@ -1688,3 +1629,121 @@ void COMXAudio::CheckOutputBufferSize(void **buffer, int *oldSize, int newSize)
   memset(*buffer, 0x0, *oldSize);
 }
 
+void COMXAudio::BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout)
+{
+  int index = 0;
+  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = PCM_FRONT_LEFT           ;
+  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = PCM_FRONT_RIGHT          ;
+  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = PCM_FRONT_CENTER         ;
+  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = PCM_LOW_FREQUENCY        ;
+  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = PCM_BACK_LEFT            ;
+  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = PCM_BACK_RIGHT           ;
+  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
+  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
+  if (layout & AV_CH_BACK_CENTER          ) channelMap[index++] = PCM_BACK_CENTER          ;
+  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = PCM_SIDE_LEFT            ;
+  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = PCM_SIDE_RIGHT           ;
+  if (layout & AV_CH_TOP_CENTER           ) channelMap[index++] = PCM_TOP_CENTER           ;
+  if (layout & AV_CH_TOP_FRONT_LEFT       ) channelMap[index++] = PCM_TOP_FRONT_LEFT       ;
+  if (layout & AV_CH_TOP_FRONT_CENTER     ) channelMap[index++] = PCM_TOP_FRONT_CENTER     ;
+  if (layout & AV_CH_TOP_FRONT_RIGHT      ) channelMap[index++] = PCM_TOP_FRONT_RIGHT      ;
+  if (layout & AV_CH_TOP_BACK_LEFT        ) channelMap[index++] = PCM_TOP_BACK_LEFT        ;
+  if (layout & AV_CH_TOP_BACK_CENTER      ) channelMap[index++] = PCM_TOP_BACK_CENTER      ;
+  if (layout & AV_CH_TOP_BACK_RIGHT       ) channelMap[index++] = PCM_TOP_BACK_RIGHT       ;
+  while (index<OMX_AUDIO_MAXCHANNELS)
+    channelMap[index++] = PCM_INVALID;
+}
+
+// See CEA spec: Table 20, Audio InfoFrame data byte 4 for the ordering here
+int COMXAudio::BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout)
+{
+  int index = 0;
+  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = PCM_FRONT_LEFT;
+  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = PCM_FRONT_RIGHT;
+  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = PCM_LOW_FREQUENCY;
+  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = PCM_FRONT_CENTER;
+  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = PCM_BACK_LEFT;
+  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = PCM_BACK_RIGHT;
+  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = PCM_SIDE_LEFT;
+  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = PCM_SIDE_RIGHT;
+
+  while (index<OMX_AUDIO_MAXCHANNELS)
+    channelMap[index++] = PCM_INVALID;
+
+  int num_channels = 0;
+  for (index=0; index<OMX_AUDIO_MAXCHANNELS; index++)
+    if (channelMap[index] != PCM_INVALID)
+       num_channels = index+1;
+  return num_channels;
+}
+
+void COMXAudio::BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE *        channelMap, uint64_t layout)
+{
+  int index = 0;
+
+  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = OMX_AUDIO_ChannelLF;
+  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = OMX_AUDIO_ChannelRF;
+  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = OMX_AUDIO_ChannelCF;
+  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = OMX_AUDIO_ChannelLFE;
+  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = OMX_AUDIO_ChannelLR;
+  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = OMX_AUDIO_ChannelRR;
+  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = OMX_AUDIO_ChannelLS;
+  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = OMX_AUDIO_ChannelRS;
+  if (layout & AV_CH_BACK_CENTER          ) channelMap[index++] = OMX_AUDIO_ChannelCS;
+  // following are not in openmax spec, but gpu does accept them
+  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)10;
+  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)11;
+  if (layout & AV_CH_TOP_CENTER           ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)12;
+  if (layout & AV_CH_TOP_FRONT_LEFT       ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)13;
+  if (layout & AV_CH_TOP_FRONT_CENTER     ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)14;
+  if (layout & AV_CH_TOP_FRONT_RIGHT      ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)15;
+  if (layout & AV_CH_TOP_BACK_LEFT        ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)16;
+  if (layout & AV_CH_TOP_BACK_CENTER      ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)17;
+  if (layout & AV_CH_TOP_BACK_RIGHT       ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)18;
+
+  while (index<OMX_AUDIO_MAXCHANNELS)
+    channelMap[index++] = OMX_AUDIO_ChannelNone;
+}
+
+uint64_t COMXAudio::GetChannelLayout(enum PCMLayout layout)
+{
+  uint64_t layouts[] = {
+    /* 2.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT,
+    /* 2.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_LOW_FREQUENCY,
+    /* 3.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER,
+    /* 3.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_LOW_FREQUENCY,
+    /* 4.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
+    /* 4.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
+    /* 5.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
+    /* 5.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
+    /* 7.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
+    /* 7.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY
+  };
+  return (int)layout < 10 ? layouts[(int)layout] : 0;
+}
+
+CAEChannelInfo COMXAudio::GetAEChannelLayout(uint64_t layout)
+{
+  CAEChannelInfo m_channelLayout;
+  m_channelLayout.Reset();
+
+  if (layout & AV_CH_FRONT_LEFT           ) m_channelLayout += AE_CH_FL  ;
+  if (layout & AV_CH_FRONT_RIGHT          ) m_channelLayout += AE_CH_FR  ;
+  if (layout & AV_CH_FRONT_CENTER         ) m_channelLayout += AE_CH_FC  ;
+  if (layout & AV_CH_LOW_FREQUENCY        ) m_channelLayout += AE_CH_LFE ;
+  if (layout & AV_CH_BACK_LEFT            ) m_channelLayout += AE_CH_BL  ;
+  if (layout & AV_CH_BACK_RIGHT           ) m_channelLayout += AE_CH_BR  ;
+  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
+  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
+  if (layout & AV_CH_BACK_CENTER          ) m_channelLayout += AE_CH_BC  ;
+  if (layout & AV_CH_SIDE_LEFT            ) m_channelLayout += AE_CH_SL  ;
+  if (layout & AV_CH_SIDE_RIGHT           ) m_channelLayout += AE_CH_SR  ;
+  if (layout & AV_CH_TOP_CENTER           ) m_channelLayout += AE_CH_TC  ;
+  if (layout & AV_CH_TOP_FRONT_LEFT       ) m_channelLayout += AE_CH_TFL ;
+  if (layout & AV_CH_TOP_FRONT_CENTER     ) m_channelLayout += AE_CH_TFC ;
+  if (layout & AV_CH_TOP_FRONT_RIGHT      ) m_channelLayout += AE_CH_TFR ;
+  if (layout & AV_CH_TOP_BACK_LEFT        ) m_channelLayout += AE_CH_BL  ;
+  if (layout & AV_CH_TOP_BACK_CENTER      ) m_channelLayout += AE_CH_BC  ;
+  if (layout & AV_CH_TOP_BACK_RIGHT       ) m_channelLayout += AE_CH_BR  ;
+  return m_channelLayout;
+}
index a7050a0..1a223e1 100644 (file)
@@ -38,6 +38,7 @@
 #include "OMXCore.h"
 #include "DllAvCodec.h"
 #include "DllAvUtil.h"
+#include "PCMRemap.h"
 
 #include "threads/CriticalSection.h"
 
@@ -60,7 +61,7 @@ public:
   float GetCacheTime();
   float GetCacheTotal();
   COMXAudio();
-  bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, bool bUsePassthrough, bool bUseHWDecode);
+  bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode);
   bool PortSettingsChanged();
   ~COMXAudio();
 
@@ -92,12 +93,19 @@ public:
   void PrintDTS(OMX_AUDIO_PARAM_DTSTYPE *dtsparam);
   unsigned int SyncDTS(BYTE* pData, unsigned int iSize);
   unsigned int SyncAC3(BYTE* pData, unsigned int iSize);
+  void UpdateAttenuation();
 
   bool BadState() { return !m_Initialized; };
   unsigned int GetAudioRenderingLatency();
   float GetMaxLevel(double &pts);
   void VizPacket(const void* data, unsigned int len, double pts);
 
+  void BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout);
+  int BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout);
+  void BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE *channelMap, uint64_t layout);
+  uint64_t GetChannelLayout(enum PCMLayout layout);
+  CAEChannelInfo GetAEChannelLayout(uint64_t layout);
+
 private:
   IAudioCallback* m_pCallback;
   bool          m_Initialized;
@@ -109,11 +117,13 @@ private:
   unsigned int  m_BytesPerSec;
   unsigned int  m_BufferLen;
   unsigned int  m_ChunkLen;
+  unsigned int  m_InputChannels;
+  unsigned int  m_OutputChannels;
   unsigned int  m_BitsPerSample;
   float         m_maxLevel;
   float         m_amplification;
   float         m_attenuation;
-  float         m_desired_attenuation;
+  float         m_submitted;
   COMXCoreComponent *m_omx_clock;
   OMXClock       *m_av_clock;
   bool          m_settings_changed;
@@ -139,6 +149,16 @@ private:
   } vizblock_t;
   std::queue<vizblock_t> m_vizqueue;
 
+  typedef struct {
+    double pts;
+    float level;
+  } amplitudes_t;
+  std::deque<amplitudes_t> m_ampqueue;
+
+  float m_downmix_matrix[OMX_AUDIO_MAXCHANNELS*OMX_AUDIO_MAXCHANNELS];
+
+  OMX_AUDIO_CHANNELTYPE m_input_channels[OMX_AUDIO_MAXCHANNELS];
+  OMX_AUDIO_CHANNELTYPE m_output_channels[OMX_AUDIO_MAXCHANNELS];
   OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output;
   OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
   OMX_AUDIO_PARAM_DTSTYPE     m_dtsParam;
@@ -158,12 +178,6 @@ protected:
   COMXCoreTunel     m_omx_tunnel_splitter_hdmi;
   DllAvUtil         m_dllAvUtil;
 
-  OMX_AUDIO_CHANNELTYPE m_input_channels[OMX_AUDIO_MAXCHANNELS];
-
-  CAEChannelInfo    m_channelLayout;
-
-  static CAEChannelInfo    GetChannelLayout(AEAudioFormat format);
-
   static void CheckOutputBufferSize(void **buffer, int *oldSize, int newSize);
   CCriticalSection m_critSection;
 };
index ab3a778..5503a0e 100644 (file)
@@ -36,7 +36,6 @@ COMXAudioCodecOMX::COMXAudioCodecOMX()
   m_bOpenedCodec = false;
 
   m_channels = 0;
-  m_layout = 0;
   m_pFrame1 = NULL;
   m_bGotFrame = false;
   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
@@ -194,7 +193,10 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
   if(m_pCodecContext->sample_fmt != m_desiredSampleFormat)
   {
     if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
+    {
       m_dllSwResample.swr_free(&m_pConvert);
+      m_channels = m_pCodecContext->channels;
+    }
 
     if(!m_pConvert)
     {
@@ -291,16 +293,9 @@ static unsigned count_bits(int64_t value)
   return bits;
 }
 
-void COMXAudioCodecOMX::BuildChannelMap()
+uint64_t COMXAudioCodecOMX::GetChannelMap()
 {
-  if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
-    return; //nothing to do here
-
-  m_channels = m_pCodecContext->channels;
-  m_layout   = m_pCodecContext->channel_layout;
-
-  int64_t layout;
-
+  uint64_t layout;
   int bits = count_bits(m_pCodecContext->channel_layout);
   if (bits == m_pCodecContext->channels)
     layout = m_pCodecContext->channel_layout;
@@ -309,31 +304,5 @@ void COMXAudioCodecOMX::BuildChannelMap()
     CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
     layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
   }
-
-  m_channelLayout.Reset();
-
-  if (layout & AV_CH_FRONT_LEFT           ) m_channelLayout += AE_CH_FL  ;
-  if (layout & AV_CH_FRONT_RIGHT          ) m_channelLayout += AE_CH_FR  ;
-  if (layout & AV_CH_FRONT_CENTER         ) m_channelLayout += AE_CH_FC  ;
-  if (layout & AV_CH_LOW_FREQUENCY        ) m_channelLayout += AE_CH_LFE ;
-  if (layout & AV_CH_BACK_LEFT            ) m_channelLayout += AE_CH_BL  ;
-  if (layout & AV_CH_BACK_RIGHT           ) m_channelLayout += AE_CH_BR  ;
-  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
-  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
-  if (layout & AV_CH_BACK_CENTER          ) m_channelLayout += AE_CH_BC  ;
-  if (layout & AV_CH_SIDE_LEFT            ) m_channelLayout += AE_CH_SL  ;
-  if (layout & AV_CH_SIDE_RIGHT           ) m_channelLayout += AE_CH_SR  ;
-  if (layout & AV_CH_TOP_CENTER           ) m_channelLayout += AE_CH_TC  ;
-  if (layout & AV_CH_TOP_FRONT_LEFT       ) m_channelLayout += AE_CH_TFL ;
-  if (layout & AV_CH_TOP_FRONT_CENTER     ) m_channelLayout += AE_CH_TFC ;
-  if (layout & AV_CH_TOP_FRONT_RIGHT      ) m_channelLayout += AE_CH_TFR ;
-  if (layout & AV_CH_TOP_BACK_LEFT        ) m_channelLayout += AE_CH_BL  ;
-  if (layout & AV_CH_TOP_BACK_CENTER      ) m_channelLayout += AE_CH_BC  ;
-  if (layout & AV_CH_TOP_BACK_RIGHT       ) m_channelLayout += AE_CH_BR  ;
-}
-
-CAEChannelInfo COMXAudioCodecOMX::GetChannelMap()
-{
-  BuildChannelMap();
-  return m_channelLayout;
+  return layout;
 }
index 12c9b4d..343465c 100644 (file)
@@ -40,7 +40,7 @@ public:
   int GetData(BYTE** dst);
   void Reset();
   int GetChannels();
-  virtual CAEChannelInfo GetChannelMap();
+  uint64_t GetChannelMap();
   int GetSampleRate();
   int GetBitsPerSample();
   static const char* GetName() { return "FFmpeg"; }
@@ -51,7 +51,6 @@ protected:
   SwrContext*     m_pConvert;
   enum AVSampleFormat m_iSampleFormat;
   enum AVSampleFormat m_desiredSampleFormat;
-  CAEChannelInfo      m_channelLayout;
 
   AVFrame* m_pFrame1;
 
@@ -61,13 +60,10 @@ protected:
   bool m_bOpenedCodec;
 
   int     m_channels;
-  uint64_t m_layout;
 
   bool m_bFirstFrame;
   bool m_bGotFrame;
   DllAvCodec m_dllAvCodec;
   DllAvUtil m_dllAvUtil;
   DllSwResample m_dllSwResample;
-
-  void BuildChannelMap();
 };
index ce709b3..380d2cc 100644 (file)
@@ -36,6 +36,7 @@
 #include "settings/DisplaySettings.h"
 #include "settings/Settings.h"
 #include "linux/RBP.h"
+#include "utils/URIUtils.h"
 
 #define EXIF_TAG_ORIENTATION    0x0112
 
@@ -140,6 +141,28 @@ bool COMXImage::ClampLimits(unsigned int &width, unsigned int &height, unsigned
   return clamped;
 }
 
+bool COMXImage::CreateThumb(const CStdString& srcFile, unsigned int maxHeight, unsigned int maxWidth, std::string &additional_info, const CStdString& destFile)
+{
+  bool okay = false;
+  COMXImageFile file;
+  COMXImageReEnc reenc;
+  void *pDestBuffer;
+  unsigned int nDestSize;
+  if (URIUtils::HasExtension(srcFile, ".jpg|.tbn") && file.ReadFile(srcFile) && reenc.ReEncode(file, maxWidth, maxHeight, pDestBuffer, nDestSize))
+  {
+    XFILE::CFile outfile;
+    if (outfile.OpenForWrite(destFile, true))
+    {
+      outfile.Write(pDestBuffer, nDestSize);
+      outfile.Close();
+      okay = true;
+    }
+    else
+      CLog::Log(LOGERROR, "%s: can't open output file: %s\n", __func__, destFile.c_str());
+  }
+  return okay;
+}
+
 #ifdef CLASSNAME
 #undef CLASSNAME
 #endif
@@ -1101,3 +1124,407 @@ bool COMXImageEnc::CreateThumbnailFromSurface(unsigned char* buffer, unsigned in
 
   return false;
 }
+
+#ifdef CLASSNAME
+#undef CLASSNAME
+#endif
+#define CLASSNAME "COMXReEnc"
+
+COMXImageReEnc::COMXImageReEnc()
+{
+  m_encoded_buffer = NULL;
+  m_pDestBuffer = NULL;
+  m_nDestAllocSize = 0;
+}
+
+COMXImageReEnc::~COMXImageReEnc()
+{
+  Close();
+  if (m_pDestBuffer)
+    free (m_pDestBuffer);
+  m_pDestBuffer = NULL;
+  m_nDestAllocSize = 0;
+}
+
+void COMXImageReEnc::Close()
+{
+  CSingleLock lock(m_OMXSection);
+
+  if(m_omx_decoder.IsInitialized())
+  {
+    m_omx_decoder.FlushInput();
+    m_omx_decoder.FreeInputBuffers();
+  }
+  if(m_omx_encoder.IsInitialized())
+  {
+    m_omx_encoder.FlushOutput();
+    m_omx_encoder.FreeOutputBuffers();
+  }
+  if(m_omx_tunnel_decode.IsInitialized())
+    m_omx_tunnel_decode.Deestablish();
+  if(m_omx_tunnel_resize.IsInitialized())
+    m_omx_tunnel_resize.Deestablish();
+  if(m_omx_decoder.IsInitialized())
+    m_omx_decoder.Deinitialize(true);
+  if(m_omx_resize.IsInitialized())
+    m_omx_resize.Deinitialize(true);
+  if(m_omx_encoder.IsInitialized())
+    m_omx_encoder.Deinitialize(true);
+}
+
+
+
+bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, bool port_settings_changed)
+{
+  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+  // on the first port settings changed event, we create the tunnel and alloc the buffer
+  if (!port_settings_changed)
+  {
+    OMX_PARAM_PORTDEFINITIONTYPE port_def;
+    OMX_INIT_STRUCTURE(port_def);
+
+    port_def.nPortIndex = m_omx_decoder.GetOutputPort();
+    m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_decoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    // TODO: jpeg decoder can decimate by factors of 2
+    port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
+    port_def.format.image.nSliceHeight = 16;//(port_def.format.image.nFrameHeight+15) & ~15;
+    port_def.format.image.nStride = 0;
+
+    m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
+    {
+      CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
+      return false;
+    }
+
+    port_def.nPortIndex = m_omx_resize.GetInputPort();
+
+    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    port_def.nPortIndex = m_omx_resize.GetOutputPort();
+    m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+    port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
+    port_def.format.image.nFrameWidth = resize_width;
+    port_def.format.image.nFrameHeight = resize_height;
+    port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
+    port_def.format.image.nStride = 0;
+    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
+    {
+      CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
+      return false;
+    }
+
+    port_def.nPortIndex = m_omx_encoder.GetInputPort();
+    m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+    port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
+    port_def.format.image.nFrameWidth = resize_width;
+    port_def.format.image.nFrameHeight = resize_height;
+    port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
+    port_def.format.image.nStride = 0;
+    m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    port_def.nPortIndex = m_omx_encoder.GetOutputPort();
+    omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
+    port_def.format.image.eColorFormat = OMX_COLOR_FormatUnused;
+    port_def.format.image.nFrameWidth = resize_width;
+    port_def.format.image.nFrameHeight = resize_height;
+    port_def.format.image.nStride = 0;
+    port_def.format.image.nSliceHeight = 0;
+    port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
+
+    omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
+    OMX_INIT_STRUCTURE(qfactor);
+    qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
+    qfactor.nQFactor = 16;
+
+    omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    omx_err = m_omx_encoder.AllocOutputBuffers();
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
+
+    omx_err = m_omx_tunnel_decode.Establish(false);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
+      return false;
+    }
+
+    m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
+
+    omx_err = m_omx_tunnel_resize.Establish(false);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
+      return false;
+    }
+
+    omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
+    if (omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+
+    if(m_omx_encoder.BadState())
+      return false;
+  }
+  // on subsequent port settings changed event, we just copy the port settings
+  else
+  {
+    // a little surprising, make a note
+    CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
+    m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
+    m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
+
+    OMX_PARAM_PORTDEFINITIONTYPE port_def;
+    OMX_INIT_STRUCTURE(port_def);
+
+    port_def.nPortIndex = m_omx_decoder.GetOutputPort();
+    m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+    port_def.nPortIndex = m_omx_resize.GetInputPort();
+    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+
+    omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
+    if(omx_err != OMX_ErrorNone)
+    {
+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
+      return false;
+    }
+    m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
+    m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
+  }
+  return true;
+}
+
+bool COMXImageReEnc::ReEncode(COMXImageFile &srcFile, unsigned int maxWidth, unsigned int maxHeight, void * &pDestBuffer, unsigned int &nDestSize)
+{
+  CSingleLock lock(m_OMXSection);
+  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+  COMXImage::ClampLimits(maxWidth, maxHeight, srcFile.GetWidth(), srcFile.GetHeight(), srcFile.GetOrientation() & 4);
+  unsigned int demuxer_bytes = srcFile.GetImageSize();
+  unsigned char *demuxer_content = (unsigned char *)srcFile.GetImageBuffer();
+  // initial dest buffer size
+  nDestSize = 0;
+
+  if(!demuxer_content || !demuxer_bytes)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s no input buffer\n", CLASSNAME, __func__, srcFile.GetFilename());
+    return false;
+  }
+
+  if(!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
+  {
+    CLog::Log(LOGERROR, "%s::%s %s error m_omx_decoder.Initialize\n", CLASSNAME, __func__, srcFile.GetFilename());
+    return false;
+  }
+
+  // set input format
+  OMX_PARAM_PORTDEFINITIONTYPE portParam;
+  OMX_INIT_STRUCTURE(portParam);
+  portParam.nPortIndex = m_omx_decoder.GetInputPort();
+
+  omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
+  if(omx_err != OMX_ErrorNone)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+    return false;
+  }
+
+  portParam.nBufferCountActual = portParam.nBufferCountMin;
+  portParam.nBufferSize = std::max(portParam.nBufferSize, ALIGN_UP(demuxer_bytes, portParam.nBufferAlignment));
+  portParam.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
+
+  omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
+  if(omx_err != OMX_ErrorNone)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+    return false;
+  }
+
+  omx_err = m_omx_decoder.AllocInputBuffers();
+  if(omx_err != OMX_ErrorNone)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+    return false;
+  }
+
+  omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
+  if (omx_err != OMX_ErrorNone)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+    return false;
+  }
+
+  bool port_settings_changed = false, eos = false;
+  while(demuxer_bytes > 0 || !port_settings_changed || !eos)
+  {
+    long timeout = 0;
+    if (demuxer_bytes)
+    {
+       OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
+       if(omx_buffer)
+       {
+         omx_buffer->nOffset = omx_buffer->nFlags  = 0;
+
+         omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
+         memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
+
+         demuxer_content += omx_buffer->nFilledLen;
+         demuxer_bytes -= omx_buffer->nFilledLen;
+         if(demuxer_bytes == 0)
+           omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
+
+         omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
+         if (omx_err != OMX_ErrorNone)
+         {
+           CLog::Log(LOGERROR, "%s::%s %s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+           return false;
+         }
+      }
+    }
+    if (!demuxer_bytes)
+    {
+       // we've submitted all buffers so can wait now
+       timeout = 1000;
+    }
+
+    omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
+    if(omx_err == OMX_ErrorNone)
+    {
+      if (!HandlePortSettingChange(maxWidth, maxHeight, port_settings_changed))
+      {
+        CLog::Log(LOGERROR, "%s::%s %s HandlePortSettingChange() failed\n", srcFile.GetFilename(), CLASSNAME, __func__);
+        return false;
+      }
+      port_settings_changed = true;
+    }
+    else if(omx_err == OMX_ErrorStreamCorrupt)
+    {
+      CLog::Log(LOGERROR, "%s::%s %s - image not supported", CLASSNAME, __func__, srcFile.GetFilename());
+      return false;
+    }
+    else if(timeout || omx_err != OMX_ErrorTimeout)
+    {
+      CLog::Log(LOGERROR, "%s::%s %s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+      return false;
+    }
+
+    if (!m_encoded_buffer && port_settings_changed && demuxer_bytes == 0)
+    {
+      m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
+      omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
+      if(omx_err != OMX_ErrorNone)
+      {
+        CLog::Log(LOGERROR, "%s::%s %s FillThisBuffer() failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+        return false;
+      }
+    }
+    if (m_encoded_buffer)
+    {
+      omx_err = m_omx_encoder.WaitForOutputDone(1000);
+      if (omx_err != OMX_ErrorNone)
+      {
+        CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
+        return false;
+      }
+      if (!m_encoded_buffer->nFilledLen)
+      {
+        CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone no data\n", CLASSNAME, __func__, srcFile.GetFilename());
+        return false;
+      }
+      if (m_encoded_buffer->nFlags & OMX_BUFFERFLAG_EOS)
+         eos = true;
+
+      if (nDestSize + m_encoded_buffer->nFilledLen > m_nDestAllocSize)
+      {
+         m_nDestAllocSize = std::max(1024U*1024U, m_nDestAllocSize*2);
+         m_pDestBuffer = realloc(m_pDestBuffer, m_nDestAllocSize);
+      }
+      memcpy((char *)m_pDestBuffer + nDestSize, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
+      nDestSize += m_encoded_buffer->nFilledLen;
+      m_encoded_buffer = NULL;
+    }
+  }
+
+  Close();
+
+  if(m_omx_decoder.BadState())
+    return false;
+
+  pDestBuffer = m_pDestBuffer;
+  CLog::Log(LOGDEBUG, "%s::%s : %s %dx%d -> %dx%d\n", CLASSNAME, __func__, srcFile.GetFilename(), srcFile.GetWidth(), srcFile.GetHeight(), maxWidth, maxHeight);
+
+  return true;
+}
index 2f9ab94..11422b1 100644 (file)
@@ -49,6 +49,7 @@ public:
   static bool CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
       unsigned int format, unsigned int pitch, const CStdString& destFile);
   static bool ClampLimits(unsigned int &width, unsigned int &height, unsigned int m_width, unsigned int m_height, bool transposed = false);
+  static bool CreateThumb(const CStdString& srcFile, unsigned int width, unsigned int height, std::string &additional_info, const CStdString& destFile);
 };
 
 class COMXImageFile
@@ -114,4 +115,27 @@ protected:
   CCriticalSection              m_OMXSection;
 };
 
+class COMXImageReEnc
+{
+public:
+  COMXImageReEnc();
+  virtual ~COMXImageReEnc();
+
+  // Required overrides
+  void Close();
+  bool ReEncode(COMXImageFile &srcFile, unsigned int width, unsigned int height, void * &pDestBuffer, unsigned int &nDestSize);
+protected:
+  bool HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, bool port_settings_changed);
+  // Components
+  COMXCoreComponent             m_omx_decoder;
+  COMXCoreComponent             m_omx_resize;
+  COMXCoreComponent             m_omx_encoder;
+  COMXCoreTunel                 m_omx_tunnel_decode;
+  COMXCoreTunel                 m_omx_tunnel_resize;
+  OMX_BUFFERHEADERTYPE          *m_encoded_buffer;
+  CCriticalSection              m_OMXSection;
+  void                          *m_pDestBuffer;
+  unsigned int                  m_nDestAllocSize;
+};
+
 #endif
index 999ce40..7949ebc 100644 (file)
@@ -566,21 +566,14 @@ bool OMXPlayerAudio::OpenDecoder()
   /* GetDataFormat is setting up evrything */
   m_format.m_dataFormat = GetDataFormat(m_hints);
 
-  m_format.m_channelLayout.Reset();
+  uint64_t channelMap = 0;
   if (m_pAudioCodec && !m_passthrough)
-    m_format.m_channelLayout = m_pAudioCodec->GetChannelMap();
+    channelMap = m_pAudioCodec->GetChannelMap();
   else if (m_passthrough)
-  {
     // we just want to get the channel count right to stop OMXAudio.cpp rejecting stream
     // the actual layout is not used
-    if (m_nChannels > 0 ) m_format.m_channelLayout += AE_CH_FL;
-    if (m_nChannels > 1 ) m_format.m_channelLayout += AE_CH_FR;
-    if (m_nChannels > 2 ) m_format.m_channelLayout += AE_CH_FC;
-    if (m_nChannels > 3 ) m_format.m_channelLayout += AE_CH_LFE;
-    if (m_nChannels > 4 ) m_format.m_channelLayout += AE_CH_BL;
-    if (m_nChannels > 5 ) m_format.m_channelLayout += AE_CH_BR;
-  }
-  bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, m_passthrough, m_hw_decode);
+    channelMap = (1<<m_nChannels)-1;
+  bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, channelMap, m_passthrough, m_hw_decode);
 
   m_codec_name = "";
   m_bad_state  = !bAudioRenderOpen;
diff --git a/xbmc/cores/omxplayer/PCMRemap.cpp b/xbmc/cores/omxplayer/PCMRemap.cpp
new file mode 100644 (file)
index 0000000..c0733c6
--- /dev/null
@@ -0,0 +1,812 @@
+/*
+ *      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
+ *
+ */
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+#include <cstdlib>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+//#include "MathUtils.h"
+#include "PCMRemap.h"
+#include "utils/log.h"
+#include "settings/Settings.h"
+#include "settings/AdvancedSettings.h"
+#ifdef _WIN32
+#include "../win32/PlatformDefs.h"
+#endif
+
+static enum PCMChannels PCMLayoutMap[PCM_MAX_LAYOUT][PCM_MAX_CH + 1] =
+{
+  /* 2.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_INVALID},
+  /* 2.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 3.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_INVALID},
+  /* 3.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 4.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 4.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 5.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
+  /* 7.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
+  /* 7.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID}
+};
+
+/*
+  map missing output into channel @ volume level
+  the order of this table is important, mix tables can not depend on channels that have not been defined yet
+  eg, FC can only be mixed into FL, FR as they are the only channels that have been defined
+*/
+#define PCM_MAX_MIX 3
+static struct PCMMapInfo PCMDownmixTable[PCM_MAX_CH][PCM_MAX_MIX] =
+{
+  /* PCM_FRONT_LEFT */
+  {
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_RIGHT */
+  {
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_CENTER */
+  {
+    {PCM_FRONT_LEFT_OF_CENTER , 1.0},
+    {PCM_FRONT_RIGHT_OF_CENTER, 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_LOW_FREQUENCY */
+  {
+    /*
+      A/52B 7.8 paragraph 2 recomends +10db
+      but due to horrible clipping when normalize
+      is disabled we set this to 1.0
+    */
+    {PCM_FRONT_LEFT           , 1.0},//3.5},
+    {PCM_FRONT_RIGHT          , 1.0},//3.5},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_LEFT */
+  {
+    {PCM_FRONT_LEFT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_RIGHT */
+  {
+    {PCM_FRONT_RIGHT          , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_LEFT_OF_CENTER */
+  {
+    {PCM_FRONT_LEFT           , 1.0},
+    {PCM_FRONT_CENTER         , 1.0, true},
+    {PCM_INVALID}
+  },
+  /* PCM_FRONT_RIGHT_OF_CENTER */
+  {
+    {PCM_FRONT_RIGHT          , 1.0},
+    {PCM_FRONT_CENTER         , 1.0, true},
+    {PCM_INVALID}
+  },
+  /* PCM_BACK_CENTER */
+  {
+    {PCM_BACK_LEFT            , 1.0},
+    {PCM_BACK_RIGHT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_SIDE_LEFT */
+  {
+    {PCM_FRONT_LEFT           , 1.0},
+    {PCM_BACK_LEFT            , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_SIDE_RIGHT */
+  {
+    {PCM_FRONT_RIGHT          , 1.0},
+    {PCM_BACK_RIGHT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_LEFT */
+  {
+    {PCM_FRONT_LEFT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_RIGHT */
+  {
+    {PCM_FRONT_RIGHT          , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_FRONT_CENTER */
+  {
+    {PCM_TOP_FRONT_LEFT       , 1.0},
+    {PCM_TOP_FRONT_RIGHT      , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_CENTER */
+  {
+    {PCM_TOP_FRONT_LEFT       , 1.0},
+    {PCM_TOP_FRONT_RIGHT      , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_LEFT */
+  {
+    {PCM_BACK_LEFT            , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_RIGHT */
+  {
+    {PCM_BACK_RIGHT           , 1.0},
+    {PCM_INVALID}
+  },
+  /* PCM_TOP_BACK_CENTER */
+  {
+    {PCM_TOP_BACK_LEFT        , 1.0},
+    {PCM_TOP_BACK_RIGHT       , 1.0},
+    {PCM_INVALID}
+  }
+};
+
+CPCMRemap::CPCMRemap() :
+  m_inSet       (false),
+  m_outSet      (false),
+  m_inChannels  (0),
+  m_outChannels (0),
+  m_inSampleSize(0),
+  m_ignoreLayout(false),
+  m_buf(NULL),
+  m_bufsize(0),
+  m_attenuation (1.0),
+  m_attenuationInc(0.0),
+  m_attenuationMin(1.0),
+  m_sampleRate  (48000.0), //safe default
+  m_holdCounter (0),
+  m_limiterEnabled(false)
+{
+  Dispose();
+}
+
+CPCMRemap::~CPCMRemap()
+{
+  Dispose();
+}
+
+void CPCMRemap::Dispose()
+{
+  free(m_buf);
+  m_buf = NULL;
+  m_bufsize = 0;
+}
+
+/* resolves the channels recursively and returns the new index of tablePtr */
+struct PCMMapInfo* CPCMRemap::ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr)
+{
+  if (channel == PCM_INVALID) return tablePtr;
+
+  /* if its a 1 to 1 mapping, return */
+  if (m_useable[channel])
+  {
+    tablePtr->channel = channel;
+    tablePtr->level   = level;
+
+    ++tablePtr;
+    tablePtr->channel = PCM_INVALID;
+    return tablePtr;
+  } else
+    if (ifExists)
+      level /= 2;
+
+  struct PCMMapInfo *info;
+  std::vector<enum PCMChannels>::iterator itt;
+
+  for(info = PCMDownmixTable[channel]; info->channel != PCM_INVALID; ++info)
+  {
+    /* make sure we are not about to recurse into ourself */
+    bool found = false;
+    for(itt = path.begin(); itt != path.end(); ++itt)
+      if (*itt == info->channel)
+      {
+        found = true;
+        break;
+      }
+
+    if (found)
+      continue;
+
+    path.push_back(channel);
+    float  l = (info->level * (level / 100)) * 100;
+    tablePtr = ResolveChannel(info->channel, l, info->ifExists, path, tablePtr);
+    path.pop_back();
+  }
+
+  return tablePtr;
+}
+
+/*
+  Builds a lookup table without extra adjustments, useful if we simply
+  want to find out which channels are active.
+  For final adjustments, BuildMap() is used.
+*/
+void CPCMRemap::ResolveChannels()
+{
+  unsigned int in_ch, out_ch;
+  bool hasSide = false;
+  bool hasBack = false;
+
+  memset(m_useable, 0, sizeof(m_useable));
+
+  if (!m_outSet)
+  {
+    /* Output format is not known yet, assume the full configured map.
+     * Note that m_ignoreLayout-using callers normally ignore the result of
+     * this function when !m_outSet, when it is called only for an advice for
+     * the caller of SetInputFormat about the best possible output map, and
+     * they can still set their output format arbitrarily in their call to
+     * SetOutputFormat. */
+    for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
+         m_useable[*chan] = true;
+  }
+  else if (m_ignoreLayout)
+  {
+    for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
+      m_useable[m_outMap[out_ch]] = true;
+  }
+  else
+  {
+    /* figure out what channels we have and can use */
+    for(enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
+    {
+      for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
+        if (m_outMap[out_ch] == *chan)
+        {
+          m_useable[*chan] = true;
+          break;
+        }
+    }
+  }
+
+  /* force mono audio to front left and front right */
+  if (!m_ignoreLayout && m_inChannels == 1 && m_inMap[0] == PCM_FRONT_CENTER
+      && m_useable[PCM_FRONT_LEFT] && m_useable[PCM_FRONT_RIGHT])
+  {
+    CLog::Log(LOGDEBUG, "CPCMRemap: Mapping mono audio to front left and front right");
+    m_useable[PCM_FRONT_CENTER] = false;
+    m_useable[PCM_FRONT_LEFT_OF_CENTER] = false;
+    m_useable[PCM_FRONT_RIGHT_OF_CENTER] = false;
+  }
+
+  /* see if our input has side/back channels */
+  for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
+    switch(m_inMap[in_ch])
+    {
+      case PCM_SIDE_LEFT:
+      case PCM_SIDE_RIGHT:
+        hasSide = true;
+        break;
+
+      case PCM_BACK_LEFT:
+      case PCM_BACK_RIGHT:
+        hasBack = true;
+        break;
+
+      default:;
+    }
+
+  /* if our input has side, and not back channels, and our output doesnt have side channels */
+  if (hasSide && !hasBack && (!m_useable[PCM_SIDE_LEFT] || !m_useable[PCM_SIDE_RIGHT]))
+  {
+    CLog::Log(LOGDEBUG, "CPCMRemap: Forcing side channel map to back channels");
+    for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
+           if (m_inMap[in_ch] == PCM_SIDE_LEFT ) m_inMap[in_ch] = PCM_BACK_LEFT;
+      else if (m_inMap[in_ch] == PCM_SIDE_RIGHT) m_inMap[in_ch] = PCM_BACK_RIGHT;
+  }
+
+  /* resolve all the channels */
+  struct PCMMapInfo table[PCM_MAX_CH + 1], *info, *dst;
+  std::vector<enum PCMChannels> path;
+
+  for (int i = 0; i < PCM_MAX_CH + 1; i++)
+  {
+    for (int j = 0; j < PCM_MAX_CH + 1; j++)
+      m_lookupMap[i][j].channel = PCM_INVALID;
+  }
+
+  memset(m_counts, 0, sizeof(m_counts));
+  for(in_ch = 0; in_ch < m_inChannels; ++in_ch) {
+
+    for (int i = 0; i < PCM_MAX_CH + 1; i++)
+      table[i].channel = PCM_INVALID;
+
+    ResolveChannel(m_inMap[in_ch], 1.0f, false, path, table);
+    for(info = table; info->channel != PCM_INVALID; ++info)
+    {
+      /* find the end of the table */
+      for(dst = m_lookupMap[info->channel]; dst->channel != PCM_INVALID; ++dst);
+
+      /* append it to the table and set its input offset */
+      dst->channel   = m_inMap[in_ch];
+      dst->in_offset = in_ch * 2;
+      dst->level     = info->level;
+      m_counts[dst->channel]++;
+    }
+  }
+}
+
+/*
+  builds a lookup table to convert from the input mapping to the output
+  mapping, this decreases the amount of work per sample to remap it.
+*/
+void CPCMRemap::BuildMap()
+{
+  struct PCMMapInfo *dst;
+  unsigned int out_ch;
+
+  if (!m_inSet || !m_outSet) return;
+
+  m_inStride  = m_inSampleSize * m_inChannels ;
+  m_outStride = m_inSampleSize * m_outChannels;
+
+  /* see if we need to normalize the levels */
+  bool dontnormalize = CSettings::Get().GetBool("audiooutput.normalizelevels");
+  CLog::Log(LOGDEBUG, "CPCMRemap: Downmix normalization is %s", (dontnormalize ? "disabled" : "enabled"));
+
+  ResolveChannels();
+
+  /* convert the levels into RMS values */
+  float loudest    = 0.0;
+  bool  hasLoudest = false;
+
+  for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
+  {
+    float scale = 0;
+    int count = 0;
+    for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
+    {
+      dst->copy  = false;
+      dst->level = dst->level / sqrt((float)m_counts[dst->channel]);
+      scale     += dst->level;
+      ++count;
+    }
+
+    /* if there is only 1 channel to mix, and the level is 1.0, then just copy the channel */
+    dst = m_lookupMap[m_outMap[out_ch]];
+    if (count == 1 && dst->level > 0.99 && dst->level < 1.01)
+      dst->copy = true;
+
+    /* normalize the levels if it is turned on */
+    if (!dontnormalize)
+      for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
+      {
+        dst->level /= scale;
+        /* find the loudest output level we have that is not 1-1 */
+        if (dst->level < 1.0 && loudest < dst->level)
+        {
+          loudest    = dst->level;
+          hasLoudest = true;
+        }
+      }
+  }
+
+  /* adjust the channels that are too loud */
+  for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
+  {
+    CStdString s = "", f;
+    for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
+    {
+      if (hasLoudest && dst->copy)
+      {
+        dst->level = loudest;
+        dst->copy  = false;
+      }
+
+      f.Format("%s(%f%s) ",  PCMChannelStr(dst->channel).c_str(), dst->level, dst->copy ? "*" : "");
+      s += f;
+    }
+    CLog::Log(LOGDEBUG, "CPCMRemap: %s = %s\n", PCMChannelStr(m_outMap[out_ch]).c_str(), s.c_str());
+  }
+}
+
+void CPCMRemap::DumpMap(CStdString info, unsigned int channels, enum PCMChannels *channelMap)
+{
+  if (channelMap == NULL)
+  {
+    CLog::Log(LOGINFO, "CPCMRemap: %s channel map: NULL", info.c_str());
+    return;
+  }
+
+  CStdString mapping;
+  for(unsigned int i = 0; i < channels; ++i)
+    mapping += ((i == 0) ? "" : ",") + PCMChannelStr(channelMap[i]);
+
+  CLog::Log(LOGINFO, "CPCMRemap: %s channel map: %s\n", info.c_str(), mapping.c_str());
+}
+
+void CPCMRemap::Reset()
+{
+  m_inSet  = false;
+  m_outSet = false;
+  Dispose();
+}
+
+/* sets the input format, and returns the requested channel layout */
+enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate)
+{
+  m_inChannels   = channels;
+  m_inSampleSize = sampleSize;
+  m_sampleRate   = sampleRate;
+  m_inSet        = channelMap != NULL;
+  if (channelMap)
+    memcpy(m_inMap, channelMap, sizeof(enum PCMChannels) * channels);
+
+  /* get the audio layout, and count the channels in it */
+  m_channelLayout  = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
+  if (m_channelLayout >= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0;
+
+
+  DumpMap("I", channels, channelMap);
+  BuildMap();
+
+  /* now remove the empty channels from PCMLayoutMap;
+   * we don't perform upmixing so we want the minimum amount of those */
+  if (channelMap) {
+    if (!m_outSet)
+      ResolveChannels(); /* Do basic channel resolving to find out the empty channels;
+                          * If m_outSet == true, this was done already by BuildMap() above */
+    int i = 0;
+    for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
+      if (m_lookupMap[*chan][0].channel != PCM_INVALID) {
+        /* something is mapped here, so add the channel */
+        m_layoutMap[i++] = *chan;
+      }
+    m_layoutMap[i] = PCM_INVALID;
+  } else
+    memcpy(m_layoutMap, PCMLayoutMap[m_channelLayout], sizeof(PCMLayoutMap[m_channelLayout]));
+
+  m_attenuation = 1.0;
+  m_attenuationInc = 1.0;
+  m_holdCounter = 0;
+
+  return m_layoutMap;
+}
+
+/* sets the output format supported by the audio renderer */
+void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout/* = false */)
+{
+  m_outChannels   = channels;
+  m_outSet        = channelMap != NULL;
+  m_ignoreLayout  = ignoreLayout;
+  if (channelMap)
+    memcpy(m_outMap, channelMap, sizeof(enum PCMChannels) * channels);
+
+  DumpMap("O", channels, channelMap);
+  BuildMap();
+
+  m_attenuation = 1.0;
+  m_attenuationInc = 1.0;
+  m_holdCounter = 0;
+}
+
+#if 0
+void CPCMRemap::Remap(void *data, void *out, unsigned int samples, long drc)
+{
+  float gain = 1.0f;
+  if (drc > 0)
+    gain = pow(10.0f, (float)drc / 2000.0f);
+
+  Remap(data, out, samples, gain);
+}
+
+/* remap the supplied data into out, which must be pre-allocated */
+void CPCMRemap::Remap(void *data, void *out, unsigned int samples, float gain /*= 1.0f*/)
+{
+  CheckBufferSize(samples * m_outChannels * sizeof(float));
+
+  //set output buffer to 0
+  memset(out, 0, samples * m_outChannels * m_inSampleSize);
+
+  //set intermediate buffer to 0
+  memset(m_buf, 0, m_bufsize);
+
+  ProcessInput(data, out, samples, gain);
+  AddGain(m_buf, samples * m_outChannels, gain);
+  ProcessLimiter(samples, gain);
+  ProcessOutput(out, samples, gain);
+}
+
+void CPCMRemap::CheckBufferSize(int size)
+{
+  if (m_bufsize < size)
+  {
+    m_bufsize = size;
+    m_buf = (float*)realloc(m_buf, m_bufsize);
+  }
+}
+
+void CPCMRemap::ProcessInput(void* data, void* out, unsigned int samples, float gain)
+{
+  for (unsigned int ch = 0; ch < m_outChannels; ch++)
+  {
+    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
+    if (info->channel == PCM_INVALID)
+      continue;
+
+    if (info->copy && gain == 1.0f) //do direct copy
+    {
+      uint8_t* src = (uint8_t*)data + info->in_offset;
+      uint8_t* dst = (uint8_t*)out  + ch * m_inSampleSize;
+      uint8_t* dstend = dst + samples * m_outStride;
+      while (dst != dstend)
+      {
+        *(int16_t*)dst = *(int16_t*)src;
+        src += m_inStride;
+        dst += m_outStride;
+      }
+    }
+    else //needs some volume change or mixing, put into intermediate buffer
+    {
+      for(; info->channel != PCM_INVALID; info++)
+      {
+        uint8_t* src = (uint8_t*)data + info->in_offset;
+        float*   dst = m_buf + ch;
+        float*   dstend = dst + samples * m_outChannels;
+        while (dst != dstend)
+        {
+          *dst += (float)(*(int16_t*)src) * info->level;
+          src += m_inStride;
+          dst += m_outChannels;
+        }
+      }
+    }
+  }
+}
+
+void CPCMRemap::AddGain(float* buf, unsigned int samples, float gain)
+{
+  if (gain != 1.0f) //needs a gain change
+  {
+    float* ptr = m_buf;
+    float* end = m_buf + samples;
+    while (ptr != end)
+      *(ptr++) *= gain;
+  }
+}
+
+void CPCMRemap::ProcessLimiter(unsigned int samples, float gain)
+{
+  //check total gain for each output channel
+  float highestgain = 1.0f;
+  for (unsigned int ch = 0; ch < m_outChannels; ch++)
+  {
+    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
+    if (info->channel == PCM_INVALID)
+      continue;
+
+    float chgain = 0.0f;
+    for(; info->channel != PCM_INVALID; info++)
+      chgain += info->level * gain;
+
+    if (chgain > highestgain)
+      highestgain = chgain;
+  }
+
+  m_attenuationMin = 1.0f;
+
+  //if one of the channels can clip, enable a limiter
+  if (highestgain > 1.0001f)
+  {
+    m_attenuationMin = m_attenuation;
+
+    if (!m_limiterEnabled)
+    {
+      CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, enabling limiter", highestgain);
+      m_limiterEnabled = true;
+    }
+
+    for (unsigned int i = 0; i < samples; i++)
+    {
+      //for each collection of samples, get the highest absolute value
+      float maxAbs = 0.0f;
+      for (unsigned int outch = 0; outch < m_outChannels; outch++)
+      {
+        float absval = fabs(m_buf[i * m_outChannels + outch]) / 32768.0f;
+        if (maxAbs < absval)
+          maxAbs = absval;
+      }
+
+      //if attenuatedAbs is higher than 1.0f, audio is clipping
+      float attenuatedAbs = maxAbs * m_attenuation;
+      if (attenuatedAbs > 1.0f)
+      {
+        //set m_attenuation so that m_attenuation * sample is the maximum output value
+        m_attenuation = 1.0f / maxAbs;
+        if (m_attenuation < m_attenuationMin)
+          m_attenuationMin = m_attenuation;
+        //value to add to m_attenuation to make it 1.0f
+        m_attenuationInc = 1.0f - m_attenuation;
+        //amount of samples to hold m_attenuation
+        m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
+      }
+      else if (m_attenuation < 1.0f && attenuatedAbs > 0.95f)
+      {
+        //if we're attenuating and we get within 5% of clipping, hold m_attenuation
+        m_attenuationInc = 1.0f - m_attenuation;
+        m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
+      }
+
+      //apply attenuation
+      for (unsigned int outch = 0; outch < m_outChannels; outch++)
+        m_buf[i * m_outChannels + outch] *= m_attenuation;
+
+      if (m_holdCounter)
+      {
+        //hold m_attenuation
+        m_holdCounter--;
+      }
+      else if (m_attenuationInc > 0.0f)
+      {
+        //move m_attenuation to 1.0 in g_advancedSettings.m_limiterRelease seconds
+        m_attenuation += m_attenuationInc / m_sampleRate / g_advancedSettings.m_limiterRelease;
+        if (m_attenuation > 1.0f)
+        {
+          m_attenuation = 1.0f;
+          m_attenuationInc = 0.0f;
+        }
+      }
+    }
+  }
+  else
+  {
+    if (m_limiterEnabled)
+    {
+      CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, disabling limiter", highestgain);
+      m_limiterEnabled = false;
+    }
+
+    //reset the limiter
+    m_attenuation = 1.0f;
+    m_attenuationInc = 0.0f;
+    m_holdCounter = 0;
+  }
+}
+
+void CPCMRemap::ProcessOutput(void* out, unsigned int samples, float gain)
+{
+  //copy from intermediate buffer to output
+  for (unsigned int ch = 0; ch < m_outChannels; ch++)
+  {
+    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
+    if (info->channel == PCM_INVALID)
+      continue;
+
+    if (!info->copy || gain != 1.0f)
+    {
+      float* src = m_buf + ch;
+      uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
+      uint8_t* dstend = dst + samples * m_outStride;
+
+      while(dst != dstend)
+      {
+        *(int16_t*)dst = MathUtils::round_int(std::min(std::max(*src, (float)INT16_MIN), (float)INT16_MAX));
+        src += m_outChannels;
+        dst += m_outStride;
+      }
+    }
+  }
+}
+
+bool CPCMRemap::CanRemap()
+{
+  return (m_inSet && m_outSet);
+}
+
+int CPCMRemap::InBytesToFrames(int bytes)
+{
+  return bytes / m_inSampleSize / m_inChannels;
+}
+
+int CPCMRemap::FramesToOutBytes(int frames)
+{
+  return frames * m_inSampleSize * m_outChannels;
+}
+
+int CPCMRemap::FramesToInBytes(int frames)
+{
+  return frames * m_inSampleSize * m_inChannels;
+}
+#endif
+CStdString CPCMRemap::PCMChannelStr(enum PCMChannels ename)
+{
+  const char* PCMChannelName[] =
+  {
+    "FL",
+    "FR",
+    "CE",
+    "LFE",
+    "BL",
+    "BR",
+    "FLOC",
+    "FROC",
+    "BC",
+    "SL",
+    "SR",
+    "TFL",
+    "TFR",
+    "TFC",
+    "TC",
+    "TBL",
+    "TBR",
+    "TBC"
+  };
+
+  int namepos = (int)ename;
+  CStdString namestr;
+
+  if (namepos < 0 || namepos >= (int)(sizeof(PCMChannelName) / sizeof(const char*)))
+    namestr.Format("UNKNOWN CHANNEL:%i", namepos);
+  else
+    namestr = PCMChannelName[namepos];
+
+  return namestr;
+}
+#if 0
+CStdString CPCMRemap::PCMLayoutStr(enum PCMLayout ename)
+{
+  const char* PCMLayoutName[] =
+  {
+    "2.0",
+    "2.1",
+    "3.0",
+    "3.1",
+    "4.0",
+    "4.1",
+    "5.0",
+    "5.1",
+    "7.0",
+    "7.1"
+  };
+
+  int namepos = (int)ename;
+  CStdString namestr;
+
+  if (namepos < 0 || namepos >= (int)(sizeof(PCMLayoutName) / sizeof(const char*)))
+    namestr.Format("UNKNOWN LAYOUT:%i", namepos);
+  else
+    namestr = PCMLayoutName[namepos];
+
+  return namestr;
+}
+#endif
+
+
+void CPCMRemap::GetDownmixMatrix(float *downmix)
+{
+  for (int i=0; i<8*8; i++)
+    downmix[i] = 0.0f;
+
+  for (unsigned int ch = 0; ch < m_outChannels; ch++)
+  {
+    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
+    if (info->channel == PCM_INVALID)
+      continue;
+
+    for(; info->channel != PCM_INVALID; info++)
+      downmix[8*ch + (info->in_offset>>1)] = info->level;
+  }
+}
diff --git a/xbmc/cores/omxplayer/PCMRemap.h b/xbmc/cores/omxplayer/PCMRemap.h
new file mode 100644 (file)
index 0000000..bbf8d29
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef __PCM_REMAP__H__
+#define __PCM_REMAP__H__
+
+/*
+ *      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 <stdint.h>
+#include <vector>
+#include "utils/StdString.h"
+
+#define PCM_MAX_CH 18
+enum PCMChannels
+{
+  PCM_INVALID = -1,
+  PCM_FRONT_LEFT,
+  PCM_FRONT_RIGHT,
+  PCM_FRONT_CENTER,
+  PCM_LOW_FREQUENCY,
+  PCM_BACK_LEFT,
+  PCM_BACK_RIGHT,
+  PCM_FRONT_LEFT_OF_CENTER,
+  PCM_FRONT_RIGHT_OF_CENTER,
+  PCM_BACK_CENTER,
+  PCM_SIDE_LEFT,
+  PCM_SIDE_RIGHT,
+  PCM_TOP_FRONT_LEFT,
+  PCM_TOP_FRONT_RIGHT,
+  PCM_TOP_FRONT_CENTER,
+  PCM_TOP_CENTER,
+  PCM_TOP_BACK_LEFT,
+  PCM_TOP_BACK_RIGHT,
+  PCM_TOP_BACK_CENTER
+};
+
+#define PCM_MAX_LAYOUT 10
+enum PCMLayout
+{
+  PCM_LAYOUT_2_0 = 0,
+  PCM_LAYOUT_2_1,
+  PCM_LAYOUT_3_0,
+  PCM_LAYOUT_3_1,
+  PCM_LAYOUT_4_0,
+  PCM_LAYOUT_4_1,
+  PCM_LAYOUT_5_0,
+  PCM_LAYOUT_5_1,
+  PCM_LAYOUT_7_0,
+  PCM_LAYOUT_7_1
+};
+
+struct PCMMapInfo
+{
+  enum  PCMChannels channel;
+  float level;
+  bool  ifExists;
+  int   in_offset;
+  bool  copy;
+};
+
+//!  Channels remapper class
+/*!
+   The usual set-up process:
+   - user calls SetInputFormat with the input channels information
+   - SetInputFormat responds with a channelmap corresponding to the speaker
+     layout that the user has configured, with empty (according to information
+     calculated from the input channelmap) channels removed
+   - user uses this information to create the desired output channelmap,
+     and calls SetOutputFormat to set it (if the channelmap contains channels
+     that do not exist in the configured speaker layout, they will contain
+     only silence unless ignoreLayout is true)
+ */
+
+class CPCMRemap
+{
+protected:
+  bool               m_inSet, m_outSet;
+  enum PCMLayout     m_channelLayout;
+  unsigned int       m_inChannels, m_outChannels;
+  unsigned int       m_inSampleSize;
+  enum PCMChannels   m_inMap [PCM_MAX_CH];
+  enum PCMChannels   m_outMap[PCM_MAX_CH];
+  enum PCMChannels   m_layoutMap[PCM_MAX_CH + 1];
+
+  bool               m_ignoreLayout;
+  bool               m_useable  [PCM_MAX_CH];
+  int                m_inStride, m_outStride;
+  struct PCMMapInfo  m_lookupMap[PCM_MAX_CH + 1][PCM_MAX_CH + 1];
+  int                m_counts[PCM_MAX_CH];
+
+  float*             m_buf;
+  int                m_bufsize;
+  float              m_attenuation;
+  float              m_attenuationInc;
+  float              m_attenuationMin; //lowest attenuation value during a call of Remap(), used for the codec info
+  float              m_sampleRate;
+  unsigned int       m_holdCounter;
+  bool               m_limiterEnabled;
+  bool               m_dontnormalize;
+
+  struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr);
+  void               ResolveChannels(); //!< Partial BuildMap(), just enough to see which output channels are active
+  void               BuildMap();
+  void               DumpMap(CStdString info, int unsigned channels, enum PCMChannels *channelMap);
+  void               Dispose();
+  CStdString         PCMChannelStr(enum PCMChannels ename);
+  CStdString         PCMLayoutStr(enum PCMLayout ename);
+
+  void               CheckBufferSize(int size);
+  void               ProcessInput(void* data, void* out, unsigned int samples, float gain);
+  void               AddGain(float* buf, unsigned int samples, float gain);
+  void               ProcessLimiter(unsigned int samples, float gain);
+  void               ProcessOutput(void* out, unsigned int samples, float gain);
+
+public:
+
+  CPCMRemap();
+  ~CPCMRemap();
+
+  void Reset();
+  enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate);
+  void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout = false);
+#if 0
+  void Remap(void *data, void *out, unsigned int samples, long drc);
+  void Remap(void *data, void *out, unsigned int samples, float gain = 1.0f);
+  bool CanRemap();
+  int  InBytesToFrames (int bytes );
+  int  FramesToOutBytes(int frames);
+  int  FramesToInBytes (int frames);
+#endif
+  float GetCurrentAttenuation() { return m_attenuationMin; }
+  void               GetDownmixMatrix(float *downmix);
+};
+
+#endif
index 4023c34..0e50fa9 100644 (file)
@@ -203,6 +203,7 @@ CEpgInfoTag &CEpgInfoTag::operator =(const CEpgInfoTag &other)
 
 void CEpgInfoTag::Serialize(CVariant &value) const
 {
+  value["broadcastid"] = m_iUniqueBroadcastID;
   value["rating"] = m_iStarRating;
   value["title"] = m_strTitle;
   value["plotoutline"] = m_strPlotOutline;
@@ -213,6 +214,14 @@ void CEpgInfoTag::Serialize(CVariant &value) const
   value["endtime"] = m_endTime.IsValid() ? m_endTime.GetAsDBDateTime() : StringUtils::EmptyString;
   value["runtime"] = StringUtils::Format("%d", GetDuration() / 60);
   value["firstaired"] = m_firstAired.IsValid() ? m_firstAired.GetAsDBDate() : StringUtils::EmptyString;
+  value["progress"] = Progress();
+  value["progresspercentage"] = ProgressPercentage();
+  value["episodename"] = m_strEpisodeName;
+  value["episodenum"] = m_iEpisodeNumber;
+  value["episodepart"] = m_iEpisodePart;
+  value["hastimer"] = HasTimer();
+  value["isactive"] = IsActive();
+  value["wasactive"] = WasActive();
 }
 
 bool CEpgInfoTag::Changed(void) const
index bef060e..45f8e3e 100644 (file)
@@ -58,6 +58,7 @@ void EpgSearchFilter::Reset()
   m_iChannelGroup            = EPG_SEARCH_UNSET;
   m_bIgnorePresentTimers     = true;
   m_bIgnorePresentRecordings = true;
+  m_iUniqueBroadcastId      = EPG_SEARCH_UNSET;
 }
 
 bool EpgSearchFilter::MatchGenre(const CEpgInfoTag &tag) const
@@ -106,16 +107,25 @@ bool EpgSearchFilter::MatchSearchTerm(const CEpgInfoTag &tag) const
   return bReturn;
 }
 
+bool EpgSearchFilter::MatchBroadcastId(const CEpgInfoTag &tag) const
+{
+  if (m_iUniqueBroadcastId != EPG_SEARCH_UNSET)
+    return (tag.UniqueBroadcastID() == m_iUniqueBroadcastId);
+
+  return true;
+}
+
 bool EpgSearchFilter::FilterEntry(const CEpgInfoTag &tag) const
 {
   return (MatchGenre(tag) &&
+      MatchBroadcastId(tag) &&
       MatchDuration(tag) &&
       MatchStartAndEndTimes(tag) &&
       MatchSearchTerm(tag)) &&
       (!tag.HasPVRChannel() ||
-      (MatchChannelNumber(tag) &&
-       MatchChannelGroup(tag) &&
-       (!m_bFTAOnly || !tag.ChannelTag()->IsEncrypted())));
+       (MatchChannelNumber(tag) &&
+        MatchChannelGroup(tag) &&
+        (!m_bFTAOnly || !tag.ChannelTag()->IsEncrypted())));
 }
 
 int EpgSearchFilter::RemoveDuplicates(CFileItemList &results)
index 835fade..d3a5164 100644 (file)
@@ -55,6 +55,7 @@ namespace EPG
     virtual bool MatchSearchTerm(const CEpgInfoTag &tag) const;
     virtual bool MatchChannelNumber(const CEpgInfoTag &tag) const;
     virtual bool MatchChannelGroup(const CEpgInfoTag &tag) const;
+    virtual bool MatchBroadcastId(const CEpgInfoTag &tag) const;
 
     static int RemoveDuplicates(CFileItemList &results);
 
@@ -76,5 +77,6 @@ namespace EPG
     int           m_iChannelGroup;            /*!< The group this channel belongs to */
     bool          m_bIgnorePresentTimers;     /*!< True to ignore currently present timers (future recordings), false if not */
     bool          m_bIgnorePresentRecordings; /*!< True to ignore currently active recordings, false if not */
+    int           m_iUniqueBroadcastId;       /*!< The broadcastid to search for */
   };
 }
index b96d65e..e501459 100644 (file)
@@ -310,11 +310,14 @@ void CGUIImage::SetCrossFade(unsigned int time)
     m_crossFadeTime = 1;
 }
 
-void CGUIImage::SetFileName(const CStdString& strFileName, bool setConstant)
+void CGUIImage::SetFileName(const CStdString& strFileName, bool setConstant, const bool useCache)
 {
   if (setConstant)
     m_info.SetLabel(strFileName, "", GetParentID());
 
+  // Set whether or not to use cache
+  m_texture.SetUseCache(useCache);
+
   if (m_crossFadeTime)
   {
     // set filename on the next texture
index 69b6506..c008622 100644 (file)
@@ -84,7 +84,7 @@ public:
   virtual void UpdateInfo(const CGUIListItem *item = NULL);
 
   virtual void SetInfo(const CGUIInfoLabel &info);
-  virtual void SetFileName(const CStdString& strFileName, bool setConstant = false);
+  virtual void SetFileName(const CStdString& strFileName, bool setConstant = false, const bool useCache = true);
   virtual void SetAspectRatio(const CAspectRatio &aspect);
   virtual void SetWidth(float width);
   virtual void SetHeight(float height);
index 68c9c5c..2f120a8 100644 (file)
@@ -47,7 +47,6 @@ CTextureInfo& CTextureInfo::operator=(const CTextureInfo &right)
   filename = right.filename;
   useLarge = right.useLarge;
   diffuseColor = right.diffuseColor;
-
   return *this;
 }
 
@@ -83,6 +82,7 @@ CGUITextureBase::CGUITextureBase(float posX, float posY, float width, float heig
   m_allocateDynamically = false;
   m_isAllocated = NO;
   m_invalid = true;
+  m_use_cache = true;
 }
 
 CGUITextureBase::CGUITextureBase(const CGUITextureBase &right) :
@@ -99,6 +99,7 @@ CGUITextureBase::CGUITextureBase(const CGUITextureBase &right) :
   m_diffuseColor = right.m_diffuseColor;
 
   m_allocateDynamically = right.m_allocateDynamically;
+  m_use_cache = right.m_use_cache;
 
   // defaults
   m_vertex.SetRect(m_posX, m_posY, m_posX + m_width, m_posY + m_height);
@@ -317,7 +318,7 @@ bool CGUITextureBase::AllocResources()
     if (m_isAllocated != NORMAL)
     { // use our large image background loader
       CTextureArray texture;
-      if (g_largeTextureManager.GetImage(m_info.filename, texture, !IsAllocated()))
+      if (g_largeTextureManager.GetImage(m_info.filename, texture, !IsAllocated(), m_use_cache))
       {
         m_isAllocated = LARGE;
 
@@ -656,6 +657,11 @@ bool CGUITextureBase::SetFileName(const CStdString& filename)
   return true;
 }
 
+void CGUITextureBase::SetUseCache(const bool useCache)
+{
+  m_use_cache = useCache;
+}
+
 int CGUITextureBase::GetOrientation() const
 {
   // multiply our orientations
index 5a37d42..40e75d6 100644 (file)
@@ -104,6 +104,7 @@ public:
   bool SetWidth(float width);
   bool SetHeight(float height);
   bool SetFileName(const CStdString &filename);
+  void SetUseCache(const bool useCache = true);
   bool SetAspectRatio(const CAspectRatio &aspect);
 
   const CStdString& GetFileName() const { return m_info.filename; };
@@ -146,7 +147,7 @@ protected:
 
   CRect m_vertex;       // vertex coords to render
   bool m_invalid;       // if true, we need to recalculate
-
+  bool m_use_cache;
   unsigned char m_alpha;
 
   float m_frameWidth, m_frameHeight;          // size in pixels of the actual frame within the texture
index ca4ff01..46df3d5 100644 (file)
@@ -41,6 +41,8 @@
 #include "SDLJoystick.h"
 #endif
 
+#define JOYSTICK_DEFAULT_MAP "_xbmc_"
+
 using namespace std;
 using namespace XFILE;
 
@@ -741,7 +743,7 @@ int CButtonTranslator::TranslateLircRemoteString(const char* szDevice, const cha
 #if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
 void CButtonTranslator::MapJoystickActions(int windowID, TiXmlNode *pJoystick)
 {
-  string joyname = "_xbmc_"; // default global map name
+  string joyname = JOYSTICK_DEFAULT_MAP; // default global map name
   vector<string> joynames;
   map<int, string> buttonMap;
   map<int, string> axisMap;
@@ -861,7 +863,11 @@ bool CButtonTranslator::TranslateJoystickString(int window, const char* szDevice
 
   map<string, JoystickMap>::iterator it = jmap->find(szDevice);
   if (it==jmap->end())
-    return false;
+  {
+    it = jmap->find(JOYSTICK_DEFAULT_MAP); // default global map name
+    if (it==jmap->end())
+      return false;
+  }
 
   JoystickMap wmap = it->second;
 
index 2845ad1..e1a8288 100644 (file)
@@ -40,6 +40,8 @@
 #include "music/MusicThumbLoader.h"
 #include "Util.h"
 #include "pvr/channels/PVRChannel.h"
+#include "epg/Epg.h"
+#include "epg/EpgContainer.h"
 
 using namespace MUSIC_INFO;
 using namespace JSONRPC;
@@ -278,7 +280,7 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
       if (allowFile)
       {
         if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->GetPath().IsEmpty())
-            object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
+          object["file"] = item->GetVideoInfoTag()->GetPath().c_str();
         if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetURL().IsEmpty())
           object["file"] = item->GetMusicInfoTag()->GetURL().c_str();
 
@@ -292,6 +294,8 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
     {
       if (item->HasPVRChannelInfoTag() && item->GetPVRChannelInfoTag()->ChannelID() > 0)
          object[ID] = item->GetPVRChannelInfoTag()->ChannelID();
+      else if (item->HasEPGInfoTag() && item->GetEPGInfoTag()->UniqueBroadcastID() > 0)
+         object[ID] = item->GetEPGInfoTag()->UniqueBroadcastID();
       else if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > 0)
         object[ID] = (int)item->GetMusicInfoTag()->GetDatabaseId();
       else if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > 0)
@@ -348,6 +352,8 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
 
     if (item->HasPVRChannelInfoTag())
       FillDetails(item->GetPVRChannelInfoTag(), item, fields, object, thumbLoader);
+    if (item->HasEPGInfoTag())
+      FillDetails(item->GetEPGInfoTag(), item, fields, object, thumbLoader);
     if (item->HasVideoInfoTag())
       FillDetails(item->GetVideoInfoTag(), item, fields, object, thumbLoader);
     if (item->HasMusicInfoTag())
index bc79a92..9478505 100644 (file)
@@ -161,6 +161,8 @@ JsonRpcMethodMap CJSONServiceDescription::m_methodMaps[] = {
   { "PVR.GetChannelGroupDetails",                   CPVROperations::GetChannelGroupDetails },
   { "PVR.GetChannels",                              CPVROperations::GetChannels },
   { "PVR.GetChannelDetails",                        CPVROperations::GetChannelDetails },
+  { "PVR.GetBroadcasts",                            CPVROperations::GetBroadcasts },
+  { "PVR.GetBroadcastDetails",                      CPVROperations::GetBroadcastDetails },
   { "PVR.Record",                                   CPVROperations::Record },
   { "PVR.Scan",                                     CPVROperations::Scan },
 
index bf18df3..a46b463 100644 (file)
@@ -150,6 +150,55 @@ JSONRPC_STATUS CPVROperations::GetChannelDetails(const CStdString &method, ITran
   return OK;
 }
 
+JSONRPC_STATUS CPVROperations::GetBroadcasts(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+  if (!g_PVRManager.IsStarted())
+    return FailedToExecute;
+
+  CPVRChannelGroupsContainer *channelGroupContainer = g_PVRManager.ChannelGroups();
+  if (channelGroupContainer == NULL)
+    return FailedToExecute;
+
+  CPVRChannelPtr channel = channelGroupContainer->GetChannelById((int)parameterObject["channelid"].asInteger());
+  if (channel == NULL)
+    return InvalidParams;
+
+  CEpg *channelEpg = channel->GetEPG();
+  if (channelEpg == NULL)
+    return InternalError;
+
+  CFileItemList programFull;
+  channelEpg->Get(programFull);
+
+  HandleFileItemList("broadcastid", false, "broadcasts", programFull, parameterObject, result, programFull.Size(), true);
+
+  return OK;
+}
+
+JSONRPC_STATUS CPVROperations::GetBroadcastDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+  if (!g_PVRManager.IsStarted())
+    return FailedToExecute;
+
+  EpgSearchFilter filter;
+  filter.Reset();
+  filter.m_iUniqueBroadcastId = (int)parameterObject["broadcastid"].asInteger();
+
+  CFileItemList broadcasts;
+  int resultSize = g_EpgContainer.GetEPGSearch(broadcasts, filter);
+
+  if (resultSize <= 0)
+    return InvalidParams;
+  else if (resultSize > 1)
+    return InternalError;
+
+  CFileItemPtr broadcast = broadcasts.Get(0);
+  HandleFileItem("broadcastid", false, "broadcastdetails", broadcast, parameterObject, parameterObject["properties"], result, false);
+
+  return OK;
+}
+
+
 JSONRPC_STATUS CPVROperations::Record(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
 {
   if (!g_PVRManager.IsStarted())
@@ -188,7 +237,7 @@ JSONRPC_STATUS CPVROperations::Record(const CStdString &method, ITransportLayer
     if (!g_PVRManager.ToggleRecordingOnChannel(pChannel->ChannelID()))
       return FailedToExecute;
   }
-  
+
   return ACK;
 }
 
@@ -250,4 +299,4 @@ void CPVROperations::FillChannelGroupDetails(const CPVRChannelGroupPtr &channelG
 
     result = object;
   }
-}
\ No newline at end of file
+}
index 1b0bca9..ab1afbe 100644 (file)
@@ -33,6 +33,8 @@ namespace JSONRPC
     static JSONRPC_STATUS GetChannelGroupDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
     static JSONRPC_STATUS GetChannels(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
     static JSONRPC_STATUS GetChannelDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+    static JSONRPC_STATUS GetBroadcasts(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+    static JSONRPC_STATUS GetBroadcastDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
 
     static JSONRPC_STATUS Record(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
     static JSONRPC_STATUS Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
@@ -41,4 +43,4 @@ namespace JSONRPC
     static JSONRPC_STATUS GetPropertyValue(const CStdString &property, CVariant &result);
     static void FillChannelGroupDetails(const PVR::CPVRChannelGroupPtr &channelGroup, const CVariant &parameterObject, CVariant &result, bool append = false);
   };
-}
\ No newline at end of file
+}
index 18b3cf5..e455548 100644 (file)
@@ -22,7 +22,7 @@
 namespace JSONRPC
 {
   const char* const JSONRPC_SERVICE_ID          = "http://xbmc.org/jsonrpc/ServiceDescription.json";
-  const char* const JSONRPC_SERVICE_VERSION     = "6.6.3";
+  const char* const JSONRPC_SERVICE_VERSION     = "6.7.0";
   const char* const JSONRPC_SERVICE_DESCRIPTION = "JSON-RPC API of XBMC";
 
   const char* const JSONRPC_SERVICE_TYPES[] = {  
@@ -807,6 +807,41 @@ namespace JSONRPC
         "}"
       "}"
     "}",
+    "\"PVR.Fields.Broadcast\": {"
+      "\"extends\": \"Item.Fields.Base\","
+      "\"items\": { \"type\": \"string\","
+        "\"enum\": [ \"title\", \"plot\", \"plotoutline\", \"starttime\","
+                  "\"endtime\", \"runtime\", \"progress\", \"progresspercentage\","
+                  "\"genre\", \"episodename\", \"episodenum\", \"episodepart\","
+                  "\"firstaired\", \"hastimer\", \"isactive\", \"parentalrating\","
+                  "\"wasactive\", \"thumbnail\" ]"
+      "}"
+    "}",
+    "\"PVR.Details.Broadcast\": {"
+      "\"extends\": \"Item.Details.Base\","
+      "\"properties\": {"
+        "\"broadcastid\": { \"$ref\": \"Library.Id\", \"required\": true },"
+        "\"title\": { \"type\": \"string\" },"
+        "\"plot\": { \"type\": \"string\" },"
+         "\"plotoutline\": { \"type\": \"string\" },"
+        "\"start\": { \"type\": \"string\" },"
+        "\"end\": { \"type\": \"string\" },"
+         "\"duration\": { \"type\": \"integer\" },"
+         "\"progress\": { \"type\": \"integer\" },"
+         "\"progresspercentage\": { \"type\": \"number\" },"
+         "\"path\": { \"type\": \"string\" },"
+         "\"genre\": { \"type\": \"string\" },"
+         "\"episodename\": { \"type\": \"string\" },"
+         "\"episodenum\": { \"type\": \"integer\" },"
+         "\"episodepart\": { \"type\": \"integer\" },"
+         "\"firstaired\": { \"type\": \"string\" },"
+         "\"hastimer\": { \"type\": \"boolean\" },"
+         "\"isactive\": { \"type\": \"boolean\" },"
+         "\"parentalrating\": { \"type\": \"integer\" },"
+         "\"wasactive\": { \"type\": \"boolean\" },"
+        "\"thumbnail\": { \"type\": \"string\" }"
+      "}"
+    "}",
     "\"Profiles.Password\": {"
       "\"type\": \"object\","
       "\"properties\": {"
@@ -2926,6 +2961,40 @@ namespace JSONRPC
         "}"
       "}"
     "}",
+    "\"PVR.GetBroadcasts\": {"
+      "\"type\": \"method\","
+      "\"description\": \"Retrieves the program of a specific channel\","
+      "\"transport\": \"Response\","
+      "\"permission\": \"ReadData\","
+      "\"params\": ["
+        "{ \"name\": \"channelid\", \"$ref\": \"Library.Id\", \"required\": true },"
+             "{ \"name\": \"properties\", \"$ref\": \"PVR.Fields.Broadcast\" },"
+             "{ \"name\": \"limits\", \"$ref\": \"List.Limits\" }"
+           "],"
+      "\"returns\": { \"type\": \"object\","
+        "\"properties\": {"
+          "\"limits\": { \"$ref\": \"List.LimitsReturned\", \"required\": true },"
+          "\"broadcasts\": { \"type\": \"array\", \"required\": true,"
+            "\"items\": { \"$ref\": \"PVR.Details.Broadcast\" }"
+          "}"
+        "}"
+      "}"
+    "}",
+    "\"PVR.GetBroadcastDetails\": {"
+      "\"type\": \"method\","
+      "\"description\": \"Retrieves the details of a specific broadcast\","
+      "\"transport\": \"Response\","
+      "\"permission\": \"ReadData\","
+      "\"params\": ["
+        "{ \"name\": \"broadcastid\", \"$ref\": \"Library.Id\", \"required\": true },"
+        "{ \"name\": \"properties\", \"$ref\": \"PVR.Fields.Broadcast\" }"
+      "],"
+      "\"returns\": { \"type\": \"object\","
+        "\"properties\": {"
+          "\"broadcastdetails\": { \"$ref\": \"PVR.Details.Broadcast\" }"
+        "}"
+      "}"
+    "}",
     "\"PVR.Record\": {"
       "\"type\": \"method\","
       "\"description\": \"Toggle recording of a channel\","
index 0c15e2b..d797863 100644 (file)
       }
     }
   },
+  "PVR.GetBroadcasts": {
+    "type": "method",
+    "description": "Retrieves the program of a specific channel",
+    "transport": "Response",
+    "permission": "ReadData",
+    "params": [
+      { "name": "channelid", "$ref": "Library.Id", "required": true },
+      { "name": "properties", "$ref": "PVR.Fields.Broadcast" },
+      { "name": "limits", "$ref": "List.Limits" }
+    ],
+    "returns": { "type": "object",
+      "properties": {
+        "limits": { "$ref": "List.LimitsReturned", "required": true },
+        "broadcasts": { "type": "array", "required": true,
+          "items": { "$ref": "PVR.Details.Broadcast" }
+        }
+      }
+    }
+  },
+  "PVR.GetBroadcastDetails": {
+    "type": "method",
+    "description": "Retrieves the details of a specific broadcast",
+    "transport": "Response",
+    "permission": "ReadData",
+    "params": [
+      { "name": "broadcastid", "$ref": "Library.Id", "required": true },
+      { "name": "properties", "$ref": "PVR.Fields.Broadcast" }
+    ],
+    "returns": { "type": "object",
+      "properties": {
+        "broadcastdetails": { "$ref": "PVR.Details.Broadcast" }
+      }
+    }
+  },      
   "PVR.Record": {
     "type": "method",
     "description": "Toggle recording of a channel",
index f134bb2..d6fd091 100644 (file)
       }
     }
   },
+  "PVR.Fields.Broadcast": {
+    "extends": "Item.Fields.Base",
+    "items": { "type": "string",
+      "enum": [ "title", "plot", "plotoutline", "starttime",
+                "endtime", "runtime", "progress", "progresspercentage",
+                "genre", "episodename", "episodenum", "episodepart",
+                "firstaired", "hastimer", "isactive", "parentalrating",
+                "wasactive", "thumbnail" ]
+    }
+  },
+  "PVR.Details.Broadcast": {"
+    "extends": "Item.Details.Base",
+    "properties": {"
+      "broadcastid": { "$ref": "Library.Id", "required": true },
+      "title": { "type": "string" },
+      "plot": { "type": "string" },
+      "plotoutline": { "type": "string" },
+      "starttime": { "type": "string" },
+      "endtime": { "type": "string" },
+      "runtime": { "type": "integer" },
+      "progress": { "type": "integer" },
+      "progresspercentage": { "type": "number" },
+      "genre": { "type": "string" },
+      "episodename": { "type": "string" },
+      "episodenum": { "type": "integer" },
+      "episodepart": { "type": "integer" },
+      "firstaired": { "type": "string" },
+      "hastimer": { "type": "boolean" },
+      "isactive": { "type": "boolean" },
+      "rating": { "type": "integer" },
+      "wasactive": { "type": "boolean" },
+      "thumbnail": { "type": "string" }
+    }
+  },
   "Profiles.Password": {
     "type": "object",
     "properties": {
index 020b80e..f3fcac7 100644 (file)
@@ -417,13 +417,13 @@ namespace XBMCAddon
         sscanf(_colorDiffuse, "%x", &colorDiffuse);
     }
 
-    void ControlImage::setImage(const char* imageFilename) throw (UnimplementedException)
+    void ControlImage::setImage(const char* imageFilename, const bool useCache) throw (UnimplementedException)
     {
       strFileName = imageFilename;
 
       LOCKGUI;
       if (pGUIControl)
-        ((CGUIImage*)pGUIControl)->SetFileName(strFileName);
+        ((CGUIImage*)pGUIControl)->SetFileName(strFileName, false, useCache);
     }
 
     void ControlImage::setColorDiffuse(const char* cColorDiffuse) throw (UnimplementedException)
index 743ddb1..b01ea46 100644 (file)
@@ -950,14 +950,15 @@ namespace XBMCAddon
                    const char* colorDiffuse = NULL);
 
       /**
-       * setImage(filename) -- Changes the image.
+       * setImage(filename, useCache) -- Changes the image.
        * 
        * filename       : string - image filename.
+       * useCache       : [opt] bool - true/use cache, false/don't use cache
        * 
        * example:
        *   - self.image.setImage('special://home/scripts/test.png')
        */
-      virtual void setImage(const char* imageFilename) throw (UnimplementedException);
+      virtual void setImage(const char* imageFilename, const bool useCache = true) throw (UnimplementedException);
 
       /**
        * setColorDiffuse(colorDiffuse) -- Changes the images color.
index 833c255..f70699c 100644 (file)
@@ -126,6 +126,8 @@ bool CSettingControl::setAttributes(const std::string &strAttributes)
       controlAttributes |= (int)SettingControlAttributeHidden;
     else if (StringUtils::EqualsNoCase(*attribute, "new"))
       controlAttributes |= (int)SettingControlAttributeVerifyNew;
+    else if (StringUtils::EqualsNoCase(*attribute, "hide_value"))
+      controlAttributes |= (int)SettingControlAttributeHideValue;
     else
       return false;
   }
index 35c1998..37db6a7 100644 (file)
@@ -48,7 +48,8 @@ typedef enum {
 typedef enum {
   SettingControlAttributeNone       = 0x0,
   SettingControlAttributeHidden     = 0x1,
-  SettingControlAttributeVerifyNew  = 0x2
+  SettingControlAttributeVerifyNew  = 0x2,
+  SettingControlAttributeHideValue  = 0x4
 } SettingControlAttribute;
 
 class CSettingControl
index f9dbead..eee1f92 100644 (file)
@@ -470,7 +470,8 @@ void CGUIControlButtonSetting::Update()
 
   CGUIControlBaseSetting::Update();
 
-  if (m_pSetting->GetType() == SettingTypeString)
+  if (m_pSetting->GetType() == SettingTypeString &&
+      !(m_pSetting->GetControl().GetAttributes() & SettingControlAttributeHideValue))
   {
     std::string strText = ((CSettingString *)m_pSetting)->GetValue();
     switch (m_pSetting->GetControl().GetFormat())
@@ -494,7 +495,7 @@ void CGUIControlButtonSetting::Update()
       }
 
       default:
-        return;
+        break;
     }
 
     m_pButton->SetLabel2(strText);