diff options
24 files changed, 675 insertions, 635 deletions
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml index cfdeea6fd4..3af681dfa4 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -38,91 +38,13 @@ </setting> </group> </category> - - <category id="audiooutput" label="772" help="36360"> + <category id="audiooutput"> <group id="1"> - <setting id="audiooutput.audiodevice"> - <level>1</level> - <default>HDMI</default> - <constraints> - <options>audiodevices</options> - </constraints> - <control type="list" format="string" /> - </setting> <setting id="audiooutput.dualaudio" type="boolean" label="37017" help="36542"> <level>2</level> <default>false</default> - <dependencies> - <dependency type="visible"> - <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition> - </dependency> - </dependencies> - <control type="toggle" /> - </setting> - <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543"> - <level>2</level> - <default>false</default> <control type="toggle" /> </setting> - <setting id="audiooutput.config"> - <visible>false</visible> - </setting> - <setting id="audiooutput.stereoupmix"> - <visible>false</visible> - </setting> - <setting id="audiooutput.streamsilence"> - <level>2</level> - <default>0</default> - <dependencies> - <dependency type="visible"> - <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.streamsilence</condition> - </dependency> - </dependencies> - <constraints> - <options>audiostreamsilence</options> - </constraints> - <control type="spinner" format="string" /> - </setting> - </group> - <group id="2"> - <visible>false</visible> - </group> - <group id="3"> - <setting id="audiooutput.passthrough"> - <level>2</level> - <default>false</default> - <dependencies> - <dependency type="visible"> - <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition> - </dependency> - </dependencies> - </setting> - <setting id="audiooutput.passthroughdevice"> - <visible>false</visible> - </setting> - <setting id="audiooutput.truehdpassthrough"> - <visible>false</visible> - </setting> - <setting id="audiooutput.dtshdpassthrough"> - <visible>false</visible> - </setting> - <setting id="audiooutput.eac3passthrough"> - <visible>false</visible> - </setting> - <setting id="audiooutput.ac3passthrough"> - <dependencies> - <dependency type="visible"> - <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.ac3passthrough</condition> - </dependency> - </dependencies> - </setting> - <setting id="audiooutput.dtspassthrough"> - <dependencies> - <dependency type="visible"> - <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.dtspassthrough</condition> - </dependency> - </dependencies> - </setting> </group> </category> </section> diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp index e798e0fae8..b76d30470e 100644 --- a/xbmc/cores/AudioEngine/AEFactory.cpp +++ b/xbmc/cores/AudioEngine/AEFactory.cpp @@ -33,10 +33,6 @@ #include "Engines/PulseAE/PulseAE.h" #endif -#if defined(TARGET_RASPBERRY_PI) - #include "Engines/PiAudio/PiAudioAE.h" -#endif - #include "guilib/LocalizeStrings.h" #include "settings/lib/Setting.h" #include "settings/Settings.h" @@ -55,9 +51,7 @@ bool CAEFactory::LoadEngine() { bool loaded = false; -#if defined(TARGET_RASPBERRY_PI) - return CAEFactory::LoadEngine(AE_ENGINE_PIAUDIO); -#elif defined(TARGET_DARWIN) +#if defined(TARGET_DARWIN) return CAEFactory::LoadEngine(AE_ENGINE_COREAUDIO); #endif @@ -104,9 +98,6 @@ bool CAEFactory::LoadEngine(enum AEEngine engine) #if defined(HAS_PULSEAUDIO) case AE_ENGINE_PULSE : AE = new CPulseAE(); break; #endif -#if defined(TARGET_RASPBERRY_PI) - case AE_ENGINE_PIAUDIO : AE = new PiAudioAE::CPiAudioAE(); break; -#endif default: return false; } diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp index e7fb9a3416..7dc504b515 100644 --- a/xbmc/cores/AudioEngine/AESinkFactory.cpp +++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp @@ -25,6 +25,8 @@ #include "Sinks/AESinkDirectSound.h" #elif defined(TARGET_ANDROID) #include "Sinks/AESinkAUDIOTRACK.h" +#elif defined(TARGET_RASPBERRY_PI) + #include "Sinks/AESinkPi.h" #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) #include "Sinks/AESinkALSA.h" @@ -55,6 +57,8 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver) driver == "DIRECTSOUND" || #elif defined(TARGET_ANDROID) driver == "AUDIOTRACK" || +#elif defined(TARGET_RASPBERRY_PI) + driver == "Pi" || #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) driver == "ALSA" || @@ -110,6 +114,10 @@ IAESink *CAESinkFactory::Create(std::string &device, AEAudioFormat &desiredForma if (driver.empty() || driver == "AUDIOTRACK") TRY_SINK(AUDIOTRACK) +#elif defined(TARGET_RASPBERRY_PI) + if (driver.empty() || driver == "Pi") + TRY_SINK(Pi) + #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) if (driver.empty() || driver == "ALSA") @@ -143,6 +151,8 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) ENUMERATE_SINK(WASAPI, force); #elif defined(TARGET_ANDROID) ENUMERATE_SINK(AUDIOTRACK, force); +#elif defined(TARGET_RASPBERRY_PI) + ENUMERATE_SINK(Pi, force); #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) ENUMERATE_SINK(ALSA, force); diff --git a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp deleted file mode 100644 index ccf40b0ea8..0000000000 --- a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2010-2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "PiAudioAE.h" - -using namespace PiAudioAE; -#include "Utils/AEUtil.h" - -#include "settings/Settings.h" -#include "settings/AdvancedSettings.h" -#include "windowing/WindowingFactory.h" - -#if defined(TARGET_RASPBERRY_PI) -#include "linux/RBP.h" -#endif - -CPiAudioAE::CPiAudioAE() -: CThread("CPiAudio") -{ -} - -CPiAudioAE::~CPiAudioAE() -{ -} - -bool CPiAudioAE::Initialize() -{ - UpdateStreamSilence(); - Create(); - return true; -} - -void CPiAudioAE::Process() -{ - while(!m_bStop) - { - /* thread just currently checks once a second if it's time to disable streamsilence */ - Sleep(1000); - - if (m_extSilenceTimer.IsTimePast()) - { - UpdateStreamSilence(false); - m_extSilenceTimer.Set(XbmcThreads::EndTime::InfiniteValue); - } - } -} - -void CPiAudioAE::UpdateStreamSilence() -{ - if (CSettings::Get().GetInt("audiooutput.streamsilence") > 0) - m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000; - else - m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue; - m_extSilenceTimer.Set(m_extSilenceTimeout); - UpdateStreamSilence(CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI" && - CSettings::Get().GetInt("audiooutput.streamsilence") != 0); -} - -void CPiAudioAE::UpdateStreamSilence(bool enable) -{ -#if defined(TARGET_RASPBERRY_PI) - char response[80] = ""; - char command[80] = ""; - sprintf(command, "force_audio hdmi %d", enable); - vc_gencmd(response, sizeof response, command); -#endif -} - -bool CPiAudioAE::Suspend() -{ - return true; -} - -bool CPiAudioAE::Resume() -{ - return true; -} - -float CPiAudioAE::GetVolume() -{ - return m_aeVolume; -} - -void CPiAudioAE::SetVolume(const float volume) -{ - m_aeVolume = std::max( 0.0f, std::min(1.0f, volume)); -} - -void CPiAudioAE::SetMute(const bool enabled) -{ - m_aeMuted = enabled; -} - -bool CPiAudioAE::IsMuted() -{ - return m_aeMuted; -} - -IAEStream *CPiAudioAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options) -{ - return NULL; -} - -IAEStream *CPiAudioAE::FreeStream(IAEStream *stream) -{ - // will retrigger the streamsilence timer - UpdateStreamSilence(); - return NULL; -} - -IAESound *CPiAudioAE::MakeSound(const std::string& file) -{ - return NULL; -} - -void CPiAudioAE::FreeSound(IAESound *sound) -{ -} - -bool CPiAudioAE::SupportsRaw(AEDataFormat format) -{ - bool supported = false; -#if defined(TARGET_RASPBERRY_PI) - if (CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI") - { - if (!CSettings::Get().GetBool("audiooutput.dualaudio")) - { - DllBcmHost m_DllBcmHost; - m_DllBcmHost.Load(); - if (format == AE_FMT_AC3 && CSettings::Get().GetBool("audiooutput.ac3passthrough") && - m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eAC3, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0) - supported = true; - if (format == AE_FMT_DTS && CSettings::Get().GetBool("audiooutput.dtspassthrough") && - m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eDTS, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0) - supported = true; - m_DllBcmHost.Unload(); - } - } -#endif - return supported; -} - -bool CPiAudioAE::SupportsSilenceTimeout() -{ - return true; -} - -void CPiAudioAE::OnSettingsChange(const std::string& setting) -{ - if (setting == "audiooutput.streamsilence" || setting == "audiooutput.audiodevice") - UpdateStreamSilence(); -} - -void CPiAudioAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) -{ - if (!passthrough) - { - devices.push_back(AEDevice("Analogue", "Analogue")); - devices.push_back(AEDevice("HDMI", "HDMI")); - } -} - -std::string CPiAudioAE::GetDefaultDevice(bool passthrough) -{ - return "HDMI"; -} - -bool CPiAudioAE::IsSettingVisible(const std::string &settingId) -{ - if (settingId == "audiooutput.samplerate") - return true; - - if (CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI") - { - if (settingId == "audiooutput.passthrough") - return true; - if (settingId == "audiooutput.dtspassthrough") - return true; - if (settingId == "audiooutput.ac3passthrough") - return true; - if (settingId == "audiooutput.channels") - return true; - if (settingId == "audiooutput.dualaudio") - return true; - if (settingId == "audiooutput.streamsilence") - return true; - } - return false; -} diff --git a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h deleted file mode 100644 index 944fba89d5..0000000000 --- a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once -/* - * Copyright (C) 2010-2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" -#include "threads/Thread.h" - -#include "Interfaces/AEStream.h" -#include "Interfaces/AESound.h" -#include "AEFactory.h" - -namespace PiAudioAE -{ - -class CPiAudioAE : public IAE, public CThread -{ -protected: - friend class ::CAEFactory; - CPiAudioAE(); - virtual ~CPiAudioAE(); - virtual bool Initialize(); - virtual void Process(); - -public: - virtual bool Suspend(); - virtual bool Resume(); - virtual void OnSettingsChange(const std::string& setting); - - virtual float GetVolume(); - virtual void SetVolume(const float volume); - virtual void SetMute(const bool enabled); - virtual bool IsMuted(); - virtual void SetSoundMode(const int mode) {} - - /* returns a new stream for data in the specified format */ - virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options = 0); - virtual IAEStream *FreeStream(IAEStream *stream); - - /* returns a new sound object */ - virtual IAESound *MakeSound(const std::string& file); - virtual void FreeSound(IAESound *sound); - - virtual void GarbageCollect() {}; - virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); - virtual std::string GetDefaultDevice(bool passthrough); - virtual bool IsSettingVisible(const std::string &settingId); - - virtual bool SupportsRaw(AEDataFormat format); - virtual bool SupportsSilenceTimeout(); - - virtual void OnLostDevice() {} - virtual void OnResetDevice() {} - -protected: - void UpdateStreamSilence(); - void UpdateStreamSilence(bool enable); - // polled via the interface - float m_aeVolume; - bool m_aeMuted; - int m_extSilenceTimeout; - XbmcThreads::EndTime m_extSilenceTimer; -}; -}; diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in index c1d53f55ea..7f8741082c 100644 --- a/xbmc/cores/AudioEngine/Makefile.in +++ b/xbmc/cores/AudioEngine/Makefile.in @@ -39,6 +39,8 @@ SRCS += AESinkFactory.cpp SRCS += Sinks/AESinkNULL.cpp SRCS += Sinks/AESinkProfiler.cpp +SRCS += Sinks/AESinkPi.cpp + SRCS += Engines/ActiveAE/ActiveAE.cpp SRCS += Engines/ActiveAE/ActiveAESink.cpp SRCS += Engines/ActiveAE/ActiveAEStream.cpp @@ -46,8 +48,6 @@ SRCS += Engines/ActiveAE/ActiveAESound.cpp SRCS += Engines/ActiveAE/ActiveAEResample.cpp SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp -SRCS += Engines/PiAudio/PiAudioAE.cpp - ifeq (@USE_ANDROID@,1) SRCS += Sinks/AESinkAUDIOTRACK.cpp else diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp new file mode 100644 index 0000000000..72beba4518 --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "system.h" + +#if defined(TARGET_RASPBERRY_PI) + +#include <stdint.h> +#include <limits.h> + +#include "AESinkPi.h" +#include "cores/AudioEngine/Utils/AEUtil.h" +#include "utils/log.h" +#include "settings/Settings.h" +#include "linux/RBP.h" + +#define CLASSNAME "CAESinkPi" + +#define NUM_OMX_BUFFERS 2 +#define AUDIO_PLAYBUFFER (1.0/20.0) + +CAEDeviceInfo CAESinkPi::m_info; + +CAESinkPi::CAESinkPi() : + m_sinkbuffer_size(0), + m_sinkbuffer_sec_per_byte(0), + m_Initialized(false), + m_submitted(0) +{ +} + +CAESinkPi::~CAESinkPi() +{ +} + +void CAESinkPi::SetAudioDest() +{ + OMX_ERRORTYPE omx_err = OMX_ErrorNone; + OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest; + OMX_INIT_STRUCTURE(audioDest); + if (CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue") + strncpy((char *)audioDest.sName, "local", strlen("local")); + else + strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi")); + omx_err = m_omx_render.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s::%s - m_omx_render.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err); +} + +bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device) +{ + m_initDevice = device; + m_initFormat = format; + // setup for a 50ms sink feed from SoftAE + format.m_dataFormat = AE_FMT_S16NE; + format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER; + format.m_frameSamples = format.m_channelLayout.Count(); + format.m_frameSize = format.m_frameSamples * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + format.m_sampleRate = std::max(8000U, std::min(96000U, format.m_sampleRate)); + + m_format = format; + + m_sinkbuffer_size = format.m_frameSize * format.m_frames * NUM_OMX_BUFFERS; + m_sinkbuffer_sec_per_byte = 1.0 / (double)(format.m_frameSize * format.m_sampleRate); + + CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f", CLASSNAME, __func__, + format.m_dataFormat, format.m_channelLayout.Count(), format.m_sampleRate, format.m_frameSize, m_sinkbuffer_size, 1.0/m_sinkbuffer_sec_per_byte); + + // This may be called before Application calls g_RBP.Initialise, so call it here too + g_RBP.Initialize(); + + CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__); + + OMX_ERRORTYPE omx_err = OMX_ErrorNone; + + if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) + CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); + + OMX_INIT_STRUCTURE(m_pcm_input); + m_pcm_input.nPortIndex = m_omx_render.GetInputPort(); + m_pcm_input.eNumData = OMX_NumericalDataSigned; + m_pcm_input.eEndian = OMX_EndianLittle; + m_pcm_input.bInterleaved = OMX_TRUE; + m_pcm_input.nBitPerSample = 16; + m_pcm_input.ePCMMode = OMX_AUDIO_PCMModeLinear; + m_pcm_input.nChannels = m_format.m_frameSamples; + m_pcm_input.nSamplingRate = m_format.m_sampleRate; + m_pcm_input.eChannelMapping[0] = OMX_AUDIO_ChannelLF; + m_pcm_input.eChannelMapping[1] = OMX_AUDIO_ChannelRF; + m_pcm_input.eChannelMapping[2] = OMX_AUDIO_ChannelMax; + + omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); + + m_omx_render.ResetEos(); + + SetAudioDest(); + + // set up the number/size of buffers for decoder input + OMX_PARAM_PORTDEFINITIONTYPE port_param; + OMX_INIT_STRUCTURE(port_param); + port_param.nPortIndex = m_omx_render.GetInputPort(); + + omx_err = m_omx_render.GetParameter(OMX_IndexParamPortDefinition, &port_param); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); + + port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS); + port_param.nBufferSize = m_sinkbuffer_size / port_param.nBufferCountActual; + + omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (intput) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); + + omx_err = m_omx_render.AllocInputBuffers(); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err); + + omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); + + m_Initialized = true; + return true; +} + + +void CAESinkPi::Deinitialize() +{ + CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__); + if (m_Initialized) + { + m_omx_render.FlushAll(); + m_omx_render.Deinitialize(); + m_Initialized = false; + } +} + +bool CAESinkPi::IsCompatible(const AEAudioFormat &format, const std::string &device) +{ + bool compatible = + /* compare against the requested format and the real format */ + (m_initFormat.m_sampleRate == format.m_sampleRate || m_format.m_sampleRate == format.m_sampleRate ) && + (m_initFormat.m_dataFormat == format.m_dataFormat || m_format.m_dataFormat == format.m_dataFormat ) && + (m_initFormat.m_channelLayout == format.m_channelLayout || m_format.m_channelLayout == format.m_channelLayout) && + (m_initDevice == device); + CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d = %d", CLASSNAME, __func__, format.m_dataFormat, format.m_channelLayout.Count(), format.m_sampleRate, compatible); + return compatible; +} + +double CAESinkPi::GetDelay() +{ + OMX_PARAM_U32TYPE param; + OMX_INIT_STRUCTURE(param); + + if (!m_Initialized) + return 0.0; + + param.nPortIndex = m_omx_render.GetInputPort(); + + OMX_ERRORTYPE omx_err = m_omx_render.GetConfig(OMX_IndexConfigAudioRenderingLatency, ¶m); + + if (omx_err != OMX_ErrorNone) + { + CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigAudioRenderingLatency error 0x%08x", + CLASSNAME, __func__, omx_err); + } + double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * param.nU32 * m_format.m_frameSize; + return sinkbuffer_seconds_to_empty; +} + +double CAESinkPi::GetCacheTime() +{ + return GetDelay(); +} + +double CAESinkPi::GetCacheTotal() +{ + double audioplus_buffer = AUDIO_PLAYBUFFER; + return m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer_size + audioplus_buffer; +} + +unsigned int CAESinkPi::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) +{ + unsigned int sent = 0; + + if (!m_Initialized) + return frames; + + OMX_ERRORTYPE omx_err = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *omx_buffer = NULL; + while (sent < frames) + { + int timeout = blocking ? 1000 : 0; + + // delay compared to maximum we'd like (to keep lag low) + double delay = GetDelay(); + bool too_laggy = delay - AUDIO_PLAYBUFFER > 0.0; + omx_buffer = too_laggy ? NULL : m_omx_render.GetInputBuffer(timeout); + + if (omx_buffer == NULL) + { + if (too_laggy) + { + Sleep((int)((delay - AUDIO_PLAYBUFFER) * 1000.0)); + continue; + } + if (blocking) + CLog::Log(LOGERROR, "COMXAudio::Decode timeout"); + break; + } + + omx_buffer->nFilledLen = std::min(omx_buffer->nAllocLen, (frames - sent) * m_format.m_frameSize); + omx_buffer->nTimeStamp = ToOMXTime(0); + omx_buffer->nFlags = 0; + memcpy(omx_buffer->pBuffer, (uint8_t *)data + sent * m_format.m_frameSize, omx_buffer->nFilledLen); + sent += omx_buffer->nFilledLen / m_format.m_frameSize; + + if (sent == frames) + omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + + if (delay <= 0.0 && m_submitted) + CLog::Log(LOGERROR, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames); + + omx_err = m_omx_render.EmptyThisBuffer(omx_buffer); + if (omx_err != OMX_ErrorNone) + CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err); + m_submitted += omx_buffer->nFilledLen; + } + + return sent; +} + +void CAESinkPi::Drain() +{ + int delay = (int)(GetDelay() * 1000.0); + if (delay) + Sleep(delay); + CLog::Log(LOGDEBUG, "%s:%s delay:%dms now:%dms", CLASSNAME, __func__, delay, (int)(GetDelay() * 1000.0)); +} + +void CAESinkPi::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) +{ + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); + m_info.m_sampleRates.clear(); + + m_info.m_deviceType = AE_DEVTYPE_HDMI; + m_info.m_deviceName = "HDMI"; + m_info.m_displayName = "HDMI"; + m_info.m_displayNameExtra = ""; + m_info.m_channels += AE_CH_FL; + m_info.m_channels += AE_CH_FR; + m_info.m_sampleRates.push_back(48000); + m_info.m_dataFormats.push_back(AE_FMT_S16LE); + + list.push_back(m_info); + + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); + m_info.m_sampleRates.clear(); + + m_info.m_deviceType = AE_DEVTYPE_PCM; + m_info.m_deviceName = "Analogue"; + m_info.m_displayName = "Analogue"; + m_info.m_displayNameExtra = ""; + m_info.m_channels += AE_CH_FL; + m_info.m_channels += AE_CH_FR; + m_info.m_sampleRates.push_back(48000); + m_info.m_dataFormats.push_back(AE_FMT_S16LE); + + list.push_back(m_info); +} + +#endif diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.h b/xbmc/cores/AudioEngine/Sinks/AESinkPi.h new file mode 100644 index 0000000000..1f3311560e --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.h @@ -0,0 +1,65 @@ +#pragma once +/* + * Copyright (C) 2010-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "system.h" + +#if defined(TARGET_RASPBERRY_PI) + +#include "cores/AudioEngine/Interfaces/AESink.h" +#include "Utils/AEDeviceInfo.h" + +#include "cores/omxplayer/OMXAudio.h" + +class CAESinkPi : public IAESink +{ +public: + virtual const char *GetName() { return "SinkPi"; } + + CAESinkPi(); + virtual ~CAESinkPi(); + + virtual bool Initialize(AEAudioFormat &format, std::string &device); + virtual void Deinitialize(); + virtual bool IsCompatible(const AEAudioFormat &format, const std::string &device); + + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + + static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false); +private: + void SetAudioDest(); + + std::string m_initDevice; + AEAudioFormat m_initFormat; + AEAudioFormat m_format; + unsigned int m_sinkbuffer_size; ///< total size of the buffer + double m_sinkbuffer_sec_per_byte; + static CAEDeviceInfo m_info; + bool m_Initialized; + uint32_t m_submitted; + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input; + COMXCoreComponent m_omx_render; +}; + +#endif diff --git a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitleStream.cpp b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitleStream.cpp index 30756cf2e1..5218d01b0e 100644 --- a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitleStream.cpp +++ b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitleStream.cpp @@ -23,8 +23,11 @@ #include "DVDInputStreams/DVDInputStream.h" #include "utils/CharsetConverter.h" #include "utils/Utf8Utils.h" +#include "utils/CharsetDetection.h" +#include "filesystem/File.h" using namespace std; +using XFILE::auto_buffer; CDVDSubtitleStream::CDVDSubtitleStream() { @@ -40,60 +43,51 @@ bool CDVDSubtitleStream::Open(const string& strFile) pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFile, ""); if (pInputStream && pInputStream->Open(strFile.c_str(), "")) { - unsigned char buffer[16384]; - int size_read = 0; - size_read = pInputStream->Read(buffer,3); - bool isUTF8 = false; - bool isUTF16 = false; - if (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF) - isUTF8 = true; - else if (buffer[0] == 0xFF && buffer[1] == 0xFE) + static const size_t chunksize = 64 * 1024; + auto_buffer buf; + + // read content + size_t totalread = 0; + int read; + do { - isUTF16 = true; - pInputStream->Seek(2, SEEK_SET); - } - else - pInputStream->Seek(0, SEEK_SET); + if (totalread == buf.size()) + buf.resize(buf.size() + chunksize); + + read = pInputStream->Read((uint8_t*)buf.get() + totalread, buf.size() - totalread); + if (read > 0) + totalread += read; + } while (read > 0); + + delete pInputStream; + if (!totalread) + return false; - if (isUTF16) + std::string tmpStr(buf.get(), totalread); + buf.clear(); + + std::string enc(CCharsetDetection::GetBomEncoding(tmpStr)); + if (enc == "UTF-8" || (enc.empty() && CUtf8Utils::isValidUtf8(tmpStr))) + m_stringstream << tmpStr; + else if (!enc.empty()) { - std::wstringstream wstringstream; - while( (size_read = pInputStream->Read(buffer, sizeof(buffer)-2) ) > 0 ) - { - buffer[size_read] = buffer[size_read + 1] = '\0'; - CStdStringW temp; - g_charsetConverter.utf16LEtoW(std::u16string((char16_t*)buffer),temp); - wstringstream << temp; - } - delete pInputStream; - - CStdString strUTF8; - g_charsetConverter.wToUTF8(CStdStringW(wstringstream.str()),strUTF8); - m_stringstream.str(""); - m_stringstream << strUTF8; + std::string converted; + g_charsetConverter.ToUtf8(enc, tmpStr, converted); + if (converted.empty()) + return false; + + m_stringstream << converted; } else { - while( (size_read = pInputStream->Read(buffer, sizeof(buffer)-1) ) > 0 ) - { - buffer[size_read] = '\0'; - m_stringstream << buffer; - } - delete pInputStream; - - if (!isUTF8) - isUTF8 = CUtf8Utils::isValidUtf8(m_stringstream.str()); - - if (!isUTF8) - { - CStdStringW strUTF16; - CStdString strUTF8; - g_charsetConverter.subtitleCharsetToW(m_stringstream.str(), strUTF16); - g_charsetConverter.wToUTF8(strUTF16,strUTF8); - m_stringstream.str(""); - m_stringstream << strUTF8; - } + std::string converted; + g_charsetConverter.subtitleCharsetToUtf8(tmpStr, converted); + if (converted.empty()) + return false; + + m_stringstream << converted; } + return true; } diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp index dbd065f442..440a26e71d 100644 --- a/xbmc/cores/omxplayer/OMXAudio.cpp +++ b/xbmc/cores/omxplayer/OMXAudio.cpp @@ -83,17 +83,16 @@ COMXAudio::COMXAudio() : m_submitted_eos (false ), m_failed_eos (false ) { - m_vizBufferSize = m_vizRemapBufferSize = VIS_PACKET_SIZE * sizeof(float); - m_vizRemapBuffer = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16); - m_vizBuffer = (uint8_t *)_aligned_malloc(m_vizBufferSize,16); + CAEFactory::Suspend(); + while (!CAEFactory::IsSuspended()) + Sleep(10); } COMXAudio::~COMXAudio() { Deinitialize(); - _aligned_free(m_vizRemapBuffer); - _aligned_free(m_vizBuffer); + CAEFactory::Resume(); } bool COMXAudio::PortSettingsChanged() @@ -118,12 +117,12 @@ bool COMXAudio::PortSettingsChanged() if(!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit)) return false; } - if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue") + if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue") { if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) return false; } - if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI") + if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") != "Pi:Analogue") { if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) return false; @@ -471,7 +470,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS]; enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1); // ignore layout setting for analogue - if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue") + if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue") layout = PCM_LAYOUT_2_0; // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix @@ -487,8 +486,6 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo 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); } m_SampleRate = m_format.m_sampleRate; @@ -690,9 +687,6 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo CLog::Log(LOGDEBUG, "COMXAudio::Initialize device passthrough %d hwdecode %d", m_Passthrough, m_HWDecode); - /* dummy call to inform PiAudioAE that audo is active */ - CAEFactory::MakeStream((enum AEDataFormat)0, 0, 0, (CAEChannelInfo)0, 0); - return true; } @@ -752,9 +746,6 @@ bool COMXAudio::Deinitialize() m_extradata = NULL; m_extrasize = 0; - while(!m_vizqueue.empty()) - m_vizqueue.pop(); - m_dllAvUtil.Unload(); while(!m_ampqueue.empty()) @@ -764,9 +755,6 @@ bool COMXAudio::Deinitialize() m_submitted = 0.0f; m_maxLevel = 0.0f; - /* dummy call to inform PiAudioAE that audo is inactive */ - CAEFactory::FreeStream(0); - return true; } @@ -874,62 +862,6 @@ bool COMXAudio::ApplyVolume(void) return true; } -void COMXAudio::VizPacket(const void* data, unsigned int len, double pts) -{ - /* input samples */ - unsigned int vizBufferSamples = len / (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3); - - /* input frames */ - unsigned int frames = vizBufferSamples / m_InputChannels; - float *floatBuffer = (float *)data; - - if (m_format.m_dataFormat != AE_FMT_FLOAT) - { - CAEConvert::AEConvertToFn m_convertFn = CAEConvert::ToFloat(m_format.m_dataFormat); - - /* check convert buffer */ - CheckOutputBufferSize((void **)&m_vizBuffer, &m_vizBufferSize, vizBufferSamples * (CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3)); - - /* convert to float */ - m_convertFn((uint8_t *)data, vizBufferSamples, (float *)m_vizBuffer); - floatBuffer = (float *)m_vizBuffer; - } - - // Viz channel count is 2 - CheckOutputBufferSize((void **)&m_vizRemapBuffer, &m_vizRemapBufferSize, frames * 2 * sizeof(float)); - - /* remap */ - m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames); - - /* output samples */ - vizBufferSamples = vizBufferSamples / m_InputChannels * 2; - - /* viz size is limited */ - if(vizBufferSamples > VIS_PACKET_SIZE) - vizBufferSamples = VIS_PACKET_SIZE; - - vizblock_t v; - v.pts = pts; - v.num_samples = vizBufferSamples; - memcpy(v.samples, m_vizRemapBuffer, vizBufferSamples * sizeof(float)); - m_vizqueue.push(v); - - double stamp = m_av_clock->OMXMediaTime(); - while(!m_vizqueue.empty()) - { - vizblock_t &v = m_vizqueue.front(); - /* if packet has almost reached media time (allow time for rendering delay) then display it */ - /* we'll also consume if queue gets unexpectedly long to avoid filling memory */ - if (v.pts == DVD_NOPTS_VALUE || v.pts - stamp < DVD_SEC_TO_TIME(1.0/30.0) || v.pts - stamp > DVD_SEC_TO_TIME(15.0)) - { - m_pCallback->OnAudioData(v.samples, v.num_samples); - m_vizqueue.pop(); - } - else break; - } -} - - //*********************************************************************************************** unsigned int COMXAudio::AddPackets(const void* data, unsigned int len) { @@ -947,9 +879,6 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt return len; } - if (m_pCallback && len && !(m_Passthrough || m_HWDecode)) - VizPacket(data, len, pts); - if(m_eEncoding == OMX_AUDIO_CodingDTS && m_LostSync && (m_Passthrough || m_HWDecode)) { int skip = SyncDTS((uint8_t *)data, len); diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h index 1a223e1414..804bd2aadc 100644 --- a/xbmc/cores/omxplayer/OMXAudio.h +++ b/xbmc/cores/omxplayer/OMXAudio.h @@ -98,7 +98,6 @@ public: 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); @@ -135,19 +134,8 @@ private: int m_extrasize; // stuff for visualisation double m_last_pts; - int m_vizBufferSize; - uint8_t *m_vizBuffer; - int m_vizRemapBufferSize; - uint8_t *m_vizRemapBuffer; - CAERemap m_vizRemap; bool m_submitted_eos; bool m_failed_eos; - typedef struct { - int num_samples; - float samples[VIS_PACKET_SIZE]; - double pts; - } vizblock_t; - std::queue<vizblock_t> m_vizqueue; typedef struct { double pts; diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp index 7e2199ac82..e391c0e84e 100644 --- a/xbmc/cores/omxplayer/OMXPlayer.cpp +++ b/xbmc/cores/omxplayer/OMXPlayer.cpp @@ -3303,17 +3303,7 @@ bool COMXPlayer::OpenVideoStream(int iStream, int source, bool reset) if(m_CurrentVideo.id < 0 || m_CurrentVideo.hint != hint) { - // for music file, don't open artwork as video - bool disabled = false; - CStdString extension = URIUtils::GetExtension(m_filename); - StringUtils::ToLower(extension); - if (!extension.empty() && g_advancedSettings.m_musicExtensions.find(extension) != std::string::npos) - { - CLog::Log(LOGWARNING, "%s - Ignoring video in audio filetype:%s", __FUNCTION__, m_filename.c_str()); - disabled = true; - } - - if (disabled || !m_omxPlayerVideo.OpenStream(hint)) + if (!m_omxPlayerVideo.OpenStream(hint)) { /* mark stream as disabled, to disallaw further attempts */ CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream); diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp index 7949ebcc19..27dbb5d75c 100644 --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp @@ -511,12 +511,12 @@ AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints) /* check our audio capabilties */ /* pathrought is overriding hw decode*/ - if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3)) + if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3) && !CSettings::Get().GetBool("audiooutput.dualaudio")) { dataFormat = AE_FMT_AC3; m_passthrough = true; } - if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS)) + if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS) && !CSettings::Get().GetBool("audiooutput.dualaudio")) { dataFormat = AE_FMT_DTS; m_passthrough = true; diff --git a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml index 4995b32e68..77c6a155cd 100644 --- a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml +++ b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml @@ -4,8 +4,4 @@ <defaultplayer>omxplayer</defaultplayer> <defaultdvdplayer>omxplayer</defaultdvdplayer> </video> - <audio> - <defaultplayer>omxplayer</defaultplayer> - <streamsilence>false</streamsilence> - </audio> </advancedsettings> diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h index 7a5d4e72b1..27f0beca5f 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h +++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h @@ -93,14 +93,10 @@ public: pPlayer = new COMXPlayer(callback); CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore); break; - case EPC_PAPLAYER: - pPlayer = new COMXPlayer(callback); - CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as PAPLayer", "OMXPlayer", m_eCore); - break; #else case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break; - case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break; #endif + case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break; case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break; #if defined(HAS_OMXPLAYER) case EPC_OMXPLAYER: pPlayer = new COMXPlayer(callback); break; diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp index ef489354e9..947925910b 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -42,6 +42,10 @@ CRBP::~CRBP() bool CRBP::Initialize() { + CSingleLock lock (m_critSection); + if (m_initialized) + return true; + m_initialized = m_DllBcmHost->Load(); if(!m_initialized) return false; diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h index f742934e86..9d527db46d 100644 --- a/xbmc/linux/RBP.h +++ b/xbmc/linux/RBP.h @@ -37,6 +37,7 @@ #if defined(TARGET_RASPBERRY_PI) #include "DllBCM.h" #include "OMXCore.h" +#include "threads/CriticalSection.h" class CRBP { @@ -63,6 +64,7 @@ private: int m_gpu_mem; COMXCore *m_OMX; class DllLibOMXCore; + CCriticalSection m_critSection; }; extern CRBP g_RBP; diff --git a/xbmc/utils/CharsetConverter.cpp b/xbmc/utils/CharsetConverter.cpp index 5fb0c95885..aa75d0af4a 100644 --- a/xbmc/utils/CharsetConverter.cpp +++ b/xbmc/utils/CharsetConverter.cpp @@ -271,7 +271,7 @@ enum StdConversionType /* Keep it in sync with CCharsetConverter::CInnerConverte Utf32ToUtf8, Utf32ToW, WToUtf32, - SubtitleCharsetToW, + SubtitleCharsetToUtf8, Utf8ToUserCharset, UserCharsetToUtf8, Utf32ToUserCharset, @@ -315,7 +315,7 @@ CConverterType CCharsetConverter::CInnerConverter::m_stdConversion[NumberOfStdCo /* Utf32ToUtf8 */ CConverterType(UTF32_CHARSET, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), /* Utf32ToW */ CConverterType(UTF32_CHARSET, WCHAR_CHARSET), /* WToUtf32 */ CConverterType(WCHAR_CHARSET, UTF32_CHARSET), - /* SubtitleCharsetToW */ CConverterType(SubtitleCharset, WCHAR_CHARSET), + /* SubtitleCharsetToUtf8*/CConverterType(SubtitleCharset, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), /* Utf8ToUserCharset */ CConverterType(UTF8_SOURCE, UserCharset), /* UserCharsetToUtf8 */ CConverterType(UserCharset, "UTF-8", CCharsetConverter::m_Utf8CharMaxSize), /* Utf32ToUserCharset */ CConverterType(UTF32_CHARSET, UserCharset), @@ -654,7 +654,7 @@ void CCharsetConverter::resetUserCharset(void) void CCharsetConverter::resetSubtitleCharset(void) { - CInnerConverter::m_stdConversion[SubtitleCharsetToW].Reset(); + CInnerConverter::m_stdConversion[SubtitleCharsetToUtf8].Reset(); } void CCharsetConverter::resetKaraokeCharset(void) @@ -749,9 +749,9 @@ bool CCharsetConverter::utf8ToW(const std::string& utf8StringSrc, std::wstring& return CInnerConverter::stdConvert(Utf8toW, utf8StringSrc, wStringDst, failOnBadChar); } -bool CCharsetConverter::subtitleCharsetToW(const std::string& stringSrc, std::wstring& wStringDst) +bool CCharsetConverter::subtitleCharsetToUtf8(const std::string& stringSrc, std::string& utf8StringDst) { - return CInnerConverter::stdConvert(SubtitleCharsetToW, stringSrc, wStringDst, false); + return CInnerConverter::stdConvert(SubtitleCharsetToUtf8, stringSrc, utf8StringDst, false); } bool CCharsetConverter::fromW(const std::wstring& wStringSrc, diff --git a/xbmc/utils/CharsetConverter.h b/xbmc/utils/CharsetConverter.h index 325daa8fa3..f80411fddd 100644 --- a/xbmc/utils/CharsetConverter.h +++ b/xbmc/utils/CharsetConverter.h @@ -131,7 +131,7 @@ public: static bool utf16LEtoW(const std::u16string& utf16String, std::wstring& wString); - static bool subtitleCharsetToW(const std::string& stringSrc, std::wstring& wStringDst); + static bool subtitleCharsetToUtf8(const std::string& stringSrc, std::string& utf8StringDst); static bool utf8ToStringCharset(const std::string& utf8StringSrc, std::string& stringDst); diff --git a/xbmc/utils/FileOperationJob.cpp b/xbmc/utils/FileOperationJob.cpp index 901eba99c4..b1f061294e 100644 --- a/xbmc/utils/FileOperationJob.cpp +++ b/xbmc/utils/FileOperationJob.cpp @@ -158,11 +158,6 @@ bool CFileOperationJob::DoProcess(FileAction action, CFileItemList & items, cons URIUtils::RemoveSlashAtEnd(strNoSlash); CStdString strFileName = URIUtils::GetFileName(strNoSlash); - // URL Decode for cases where source uses URL encoding and target does not - if ( URIUtils::ProtocolHasEncodedFilename(CURL(pItem->GetPath()).GetProtocol() ) - && !URIUtils::ProtocolHasEncodedFilename(CURL(strDestFile).GetProtocol() ) ) - CURL::Decode(strFileName); - // special case for upnp if (URIUtils::IsUPnP(items.GetPath()) || URIUtils::IsUPnP(pItem->GetPath())) { @@ -181,7 +176,7 @@ bool CFileOperationJob::DoProcess(FileAction action, CFileItemList & items, cons CStdString strnewDestFile; if(!strDestFile.empty()) // only do this if we have a destination - strnewDestFile = URIUtils::AddFileToFolder(strDestFile, strFileName); + strnewDestFile = URIUtils::ChangeBasePath(pItem->GetPath(), strFileName, strDestFile); // Convert (URL) encoding + slashes (if source / target differ) if (pItem->m_bIsFolder) { diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp index 5b292bc25a..1f44d6fcfc 100644 --- a/xbmc/utils/URIUtils.cpp +++ b/xbmc/utils/URIUtils.cpp @@ -395,29 +395,80 @@ bool URIUtils::GetParentPath(const CStdString& strPath, CStdString& strParent) return true; } +std::string URLEncodePath(const std::string& strPath) +{ + vector<string> segments = StringUtils::Split(strPath, "/"); + for (vector<string>::iterator i = segments.begin(); i != segments.end(); ++i) + *i = CURL::Encode(*i); + + return StringUtils::Join(segments, "/"); +} + +std::string URLDecodePath(const std::string& strPath) +{ + vector<string> segments = StringUtils::Split(strPath, "/"); + for (vector<string>::iterator i = segments.begin(); i != segments.end(); ++i) + *i = CURL::Decode(*i); + + return StringUtils::Join(segments, "/"); +} + +std::string URIUtils::ChangeBasePath(const std::string &fromPath, const std::string &fromFile, const std::string &toPath) +{ + std::string toFile = fromFile; + + // Convert back slashes to forward slashes, if required + if (IsDOSPath(fromPath) && !IsDOSPath(toPath)) + StringUtils::Replace(toFile, "\\", "/"); + + // Handle difference in URL encoded vs. not encoded + if ( ProtocolHasEncodedFilename(CURL(fromPath).GetProtocol() ) + && !ProtocolHasEncodedFilename(CURL(toPath).GetProtocol() ) ) + { + toFile = URLDecodePath(toFile); // Decode path + } + else if (!ProtocolHasEncodedFilename(CURL(fromPath).GetProtocol() ) + && ProtocolHasEncodedFilename(CURL(toPath).GetProtocol() ) ) + { + toFile = URLEncodePath(toFile); // Encode path + } + + // Convert forward slashes to back slashes, if required + if (!IsDOSPath(fromPath) && IsDOSPath(toPath)) + StringUtils::Replace(toFile, "/", "\\"); + + return AddFileToFolder(toPath, toFile); +} + CStdString URIUtils::SubstitutePath(const CStdString& strPath, bool reverse /* = false */) { for (CAdvancedSettings::StringMapping::iterator i = g_advancedSettings.m_pathSubstitutions.begin(); i != g_advancedSettings.m_pathSubstitutions.end(); i++) { + CStdString fromPath; + CStdString toPath; + if (!reverse) { - if (strncmp(strPath.c_str(), i->first.c_str(), HasSlashAtEnd(i->first.c_str()) ? i->first.size()-1 : i->first.size()) == 0) - { - if (strPath.size() > i->first.size()) - return URIUtils::AddFileToFolder(i->second, strPath.substr(i->first.size())); - else - return i->second; - } + fromPath = i->first; // Fake path + toPath = i->second; // Real path } else { - if (strncmp(strPath.c_str(), i->second.c_str(), HasSlashAtEnd(i->second.c_str()) ? i->second.size()-1 : i->second.size()) == 0) + fromPath = i->second; // Real path + toPath = i->first; // Fake path + } + + if (strncmp(strPath.c_str(), fromPath.c_str(), HasSlashAtEnd(fromPath) ? fromPath.size() - 1 : fromPath.size()) == 0) + { + if (strPath.size() > fromPath.size()) + { + CStdString strSubPathAndFileName = strPath.substr(fromPath.size()); + return ChangeBasePath(fromPath, strSubPathAndFileName, toPath); // Fix encoding + slash direction + } + else { - if (strPath.size() > i->second.size()) - return URIUtils::AddFileToFolder(i->first, strPath.substr(i->second.size())); - else - return i->first; + return toPath; } } } diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h index 146bf5cd01..cf7ea3f257 100644 --- a/xbmc/utils/URIUtils.h +++ b/xbmc/utils/URIUtils.h @@ -68,6 +68,16 @@ public: static void GetCommonPath(CStdString& strPath, const CStdString& strPath2); static CStdString GetParentPath(const CStdString& strPath); static bool GetParentPath(const CStdString& strPath, CStdString& strParent); + + /* \brief Change the base path of a URL: fromPath/fromFile -> toPath/toFile + Handles changes in path separator and filename URL encoding if necessary to derive toFile. + \param fromPath the base path of the original URL + \param fromFile the filename portion of the original URL + \param toPath the base path of the resulting URL + \return the full path. + */ + static std::string ChangeBasePath(const std::string &fromPath, const std::string &fromFile, const std::string &toPath); + static CStdString SubstitutePath(const CStdString& strPath, bool reverse = false); static bool IsAddonsPath(const CStdString& strFile); diff --git a/xbmc/utils/test/TestURIUtils.cpp b/xbmc/utils/test/TestURIUtils.cpp index 7170c46939..9af7f2fc27 100644 --- a/xbmc/utils/test/TestURIUtils.cpp +++ b/xbmc/utils/test/TestURIUtils.cpp @@ -178,12 +178,56 @@ TEST_F(TestURIUtils, SubstitutePath) { CStdString from, to, ref, var; - from = "/somepath"; - to = "/someotherpath"; + from = "C:\\My Videos"; + to = "https://myserver/some%20other%20path"; g_advancedSettings.m_pathSubstitutions.push_back(std::make_pair(from, to)); - ref = "/someotherpath/to/movie.avi"; - var = URIUtils::SubstitutePath("/somepath/to/movie.avi"); + from = "/this/path1"; + to = "/some/other/path2"; + g_advancedSettings.m_pathSubstitutions.push_back(std::make_pair(from, to)); + + from = "davs://otherserver/my%20music%20path"; + to = "D:\\Local Music\\MP3 Collection"; + g_advancedSettings.m_pathSubstitutions.push_back(std::make_pair(from, to)); + + ref = "https://myserver/some%20other%20path/sub%20dir/movie%20name.avi"; + var = URIUtils::SubstitutePath("C:\\My Videos\\sub dir\\movie name.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "C:\\My Videos\\sub dir\\movie name.avi"; + var = URIUtils::SubstitutePath("https://myserver/some%20other%20path/sub%20dir/movie%20name.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3"; + var = URIUtils::SubstitutePath("davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"; + var = URIUtils::SubstitutePath("D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/some/other/path2/to/movie.avi"; + var = URIUtils::SubstitutePath("/this/path1/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/this/path1/to/movie.avi"; + var = URIUtils::SubstitutePath("/some/other/path2/to/movie.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref, true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref, true); EXPECT_STREQ(ref.c_str(), var.c_str()); } diff --git a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp index a039fc457f..9d0e97f563 100644 --- a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp +++ b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp @@ -33,6 +33,7 @@ #include "addons/include/xbmc_vis_dll.h" #include <string.h> +#include <stdlib.h> #include <math.h> #include <stdint.h> @@ -59,16 +60,15 @@ #define glLoadIdentity() vis_shader->LoadIdentity() #define glFrustum(a,b,c,d,e,f) vis_shader->Frustum(a,b,c,d,e,f) -GLenum g_mode = GL_TRIANGLES; -float g_fWaveform[2][512]; -const char *frag = "precision mediump float; \n" +static GLenum g_mode = GL_TRIANGLES; +static const char *frag = "precision mediump float; \n" "varying lowp vec4 m_colour; \n" "void main () \n" "{ \n" " gl_FragColor = m_colour; \n" "}\n"; -const char *vert = "attribute vec4 m_attrpos;\n" +static const char *vert = "attribute vec4 m_attrpos;\n" "attribute vec4 m_attrcol;\n" "attribute vec4 m_attrcord0;\n" "attribute vec4 m_attrcord1;\n" @@ -86,24 +86,24 @@ const char *vert = "attribute vec4 m_attrpos;\n" " m_cord1 = m_attrcord1;\n" "}\n"; -CVisGUIShader *vis_shader = NULL; +static CVisGUIShader *vis_shader = NULL; #elif defined(HAS_SDL_OPENGL) #include <GL/glew.h> -GLenum g_mode = GL_FILL; +static GLenum g_mode = GL_FILL; #endif #define NUM_BANDS 16 -GLfloat x_angle = 20.0, x_speed = 0.0; -GLfloat y_angle = 45.0, y_speed = 0.5; -GLfloat z_angle = 0.0, z_speed = 0.0; -GLfloat heights[16][16], cHeights[16][16], scale; -GLfloat hSpeed = 0.05; +static GLfloat x_angle = 20.0, x_speed = 0.0; +static GLfloat y_angle = 45.0, y_speed = 0.5; +static GLfloat z_angle = 0.0, z_speed = 0.0; +static GLfloat heights[16][16], cHeights[16][16], scale; +static GLfloat hSpeed = 0.05; #if defined(HAS_SDL_OPENGL) -void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) +static void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) { if(y1 == y2) { @@ -127,7 +127,7 @@ void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, } } -void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue ) +static void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue, int index) { GLfloat width = 0.1; @@ -158,69 +158,105 @@ void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, G #elif defined(HAS_GLES) -void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue ) +static GLfloat *m_col; +static GLfloat *m_ver; +static GLushort *m_idx; + +static void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue, int index) { + if (!m_col || !m_ver || !m_idx) + return; + // avoid zero sized bars, which results in overlapping triangles of same depth and display artefacts height = std::max(height, 1e-3f); - GLfloat col[] = { - red * 0.1f, green * 0.1f, blue * 0.1f, - red * 0.2f, green * 0.2f, blue * 0.2f, - red * 0.3f, green * 0.3f, blue * 0.3f, - red * 0.4f, green * 0.4f, blue * 0.4f, - red * 0.5f, green * 0.5f, blue * 0.5f, - red * 0.6f, green * 0.6f, blue * 0.6f, - red * 0.7f, green * 0.7f, blue * 0.7f, - red * 0.8f, green * 0.8f, blue *0.8f - }; - GLfloat ver[] = { - x_offset + 0.0f, 0.0f, z_offset + 0.0f, - x_offset + 0.1f, 0.0f, z_offset + 0.0f, - x_offset + 0.1f, 0.0f, z_offset + 0.1f, - x_offset + 0.0f, 0.0f, z_offset + 0.1f, - x_offset + 0.0f, height, z_offset + 0.0f, - x_offset + 0.1f, height, z_offset + 0.0f, - x_offset + 0.1f, height, z_offset + 0.1f, - x_offset + 0.0f, height, z_offset + 0.1f - }; - - GLubyte idx[] = { - // Bottom - 0, 1, 2, - 0, 2, 3, - // Left - 0, 4, 7, - 0, 7, 3, - // Back - 3, 7, 6, - 3, 6, 2, - // Right - 1, 5, 6, - 1, 6, 2, - // Front - 0, 4, 5, - 0, 5, 1, - // Top - 4, 5, 6, - 4, 6, 7 - }; - - GLint posLoc = vis_shader->GetPosLoc(); - GLint colLoc = vis_shader->GetColLoc(); - - glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col); - glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, ver); - - glEnableVertexAttribArray(posLoc); - glEnableVertexAttribArray(colLoc); - - glDrawElements(g_mode, 36, GL_UNSIGNED_BYTE, idx); - - glDisableVertexAttribArray(posLoc); - glDisableVertexAttribArray(colLoc); + GLfloat *ver = m_ver + 3 * 8 * index; + // just need to update the height vertex, all else is the same + for (int i=0; i<8; i++) + { + ver[1] = (((i+0)>>2)&1) * height; + ver += 3; + } + // on last index, draw the object + if (index == 16*16-1) + { + GLint posLoc = vis_shader->GetPosLoc(); + GLint colLoc = vis_shader->GetColLoc(); + + glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, m_col); + glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, m_ver); + + glEnableVertexAttribArray(posLoc); + glEnableVertexAttribArray(colLoc); + + glDrawElements(g_mode, 16*16*36, GL_UNSIGNED_SHORT, m_idx); + + glDisableVertexAttribArray(posLoc); + glDisableVertexAttribArray(colLoc); + } +} + +static void init_bars(void) +{ + if (!m_col || !m_ver || !m_idx) + return; + + GLfloat x_offset, z_offset, r_base, b_base; + for(int y = 0; y < 16; y++) + { + z_offset = -1.6 + ((15 - y) * 0.2); + + b_base = y * (1.0 / 15); + r_base = 1.0 - b_base; + + for(int x = 0; x < 16; x++) + { + x_offset = -1.6 + ((float)x * 0.2); + + GLfloat red = r_base - (float(x) * (r_base / 15.0)); + GLfloat green = (float)x * (1.0 / 15); + GLfloat blue = b_base; + int index = 16*y+x; + GLfloat *col = m_col + 3 * 8 * index; + for (int i=0; i<8; i++) + { + float scale = 0.1f * i; + *col++ = red * scale; + *col++ = green * scale; + *col++ = blue * scale; + } + GLfloat *ver = m_ver + 3 * 8 * index; + for (int i=0; i<8; i++) + { + *ver++ = x_offset + (((i+1)>>1)&1) * 0.1f; + *ver++ = 0; // height - filled in later + *ver++ = z_offset + (((i+0)>>1)&1) * 0.1f; + } + GLushort *idx = m_idx + 36 * index; + GLushort startidx = 8 * index; + // Bottom + *idx++ = startidx + 0; *idx++ = startidx + 1; *idx++ = startidx + 2; + *idx++ = startidx + 0; *idx++ = startidx + 2; *idx++ = startidx + 3; + // Left + *idx++ = startidx + 0; *idx++ = startidx + 4; *idx++ = startidx + 7; + *idx++ = startidx + 0; *idx++ = startidx + 7; *idx++ = startidx + 3; + // Back + *idx++ = startidx + 3; *idx++ = startidx + 7; *idx++ = startidx + 6; + *idx++ = startidx + 3; *idx++ = startidx + 6; *idx++ = startidx + 2; + // Right + *idx++ = startidx + 1; *idx++ = startidx + 5; *idx++ = startidx + 6; + *idx++ = startidx + 1; *idx++ = startidx + 6; *idx++ = startidx + 2; + // Front + *idx++ = startidx + 0; *idx++ = startidx + 4; *idx++ = startidx + 5; + *idx++ = startidx + 0; *idx++ = startidx + 5; *idx++ = startidx + 1; + // Top + *idx++ = startidx + 4; *idx++ = startidx + 5; *idx++ = startidx + 6; + *idx++ = startidx + 4; *idx++ = startidx + 6; *idx++ = startidx + 7; + } + } } #endif -void draw_bars(void) +static void draw_bars(void) { int x,y; GLfloat x_offset, z_offset, r_base, b_base; @@ -254,7 +290,7 @@ void draw_bars(void) } draw_bar(x_offset, z_offset, cHeights[y][x], r_base - (float(x) * (r_base / 15.0)), - (float)x * (1.0 / 15), b_base); + (float)x * (1.0 / 15), b_base, 16*y+x); } } glEnd(); @@ -283,6 +319,10 @@ ADDON_STATUS ADDON_Create(void* hdl, void* props) delete vis_shader; return ADDON_STATUS_UNKNOWN; } + m_col = (GLfloat *)malloc(16*16*3*8 * sizeof(GLfloat *)); + m_ver = (GLfloat *)malloc(16*16*3*8 * sizeof(GLfloat *)); + m_idx = (GLushort *)malloc(16*16*36 * sizeof(GLushort *)); + init_bars(); #endif scale = 1.0 / log(256.0); @@ -456,6 +496,12 @@ extern "C" void ADDON_Destroy() vis_shader->Free(); delete vis_shader; } + free(m_col); + free(m_ver); + free(m_idx); + m_col = NULL; + m_ver = NULL; + m_idx = NULL; #endif } |