<?xml version="1.0" encoding="UTF-8"?>
<window>
<allowoverlay>no</allowoverlay>
- <defaultcontrol always="false">101</defaultcontrol>
<coordinates>
<system>1</system>
<left>680</left>
<onclick>PreviousMenu</onclick>
<texturefocus>DialogCloseButton-focus.png</texturefocus>
<texturenofocus>DialogCloseButton.png</texturenofocus>
- <onleft>101</onleft>
- <onright>101</onright>
- <onup>101</onup>
- <ondown>101</ondown>
<visible>system.getbool(input.enablemouse)</visible>
</control>
<control type="label">
<height>4</height>
<texture>separator.png</texture>
</control>
- <!-- ** Required ** Do not change <id> or <type> (Text box for lyrics) -->
- <control type="textbox" id="100">
- <description>textarea</description>
- <left>30</left>
- <top>130</top>
- <width>550</width>
- <height>500</height>
- <align>center</align>
- <font>font13</font>
- <textcolor>white</textcolor>
- <shadowcolor>black</shadowcolor>
- <pagecontrol>101</pagecontrol>
- </control>
- <control type="spincontrol" id="101">
- <description>Next page button</description>
- <left>520</left>
- <top>650</top>
- <subtype>page</subtype>
- <font>font12</font>
- <onleft>101</onleft>
- <onright>101</onright>
- <ondown>101</ondown>
- <onup>101</onup>
- <textcolor>blue</textcolor>
- <showonepage>true</showonepage>
- <visible>Control.IsVisible(100)</visible>
- </control>
<!-- ** Required ** Do not change <id> or <type> (Smooth scrolling list for lyrics) -->
<control type="list" id="110">
<left>30</left>
<font>font13_title</font>
<label>31203</label>
<textcolor>white</textcolor>
- <visible>Control.IsVisible(120) + ![Control.IsVisible(100) | Control.IsVisible(110)]</visible>
+ <visible>Control.IsVisible(120) + !Control.IsVisible(110)</visible>
</control>
<!-- ** Required ** Do not change <id> or <type> (Song Chooser if it gets it wrong) -->
<control type="list" id="120">
<?xml version="1.0" encoding="UTF-8"?>
-<addon id="xbmc.json" version="6.11.0" provider-name="Team XBMC">
+<addon id="xbmc.json" version="6.12.0" provider-name="Team XBMC">
<backwards-compatibility abi="6.0.0"/>
<requires>
<import addon="xbmc.core" version="0.1.0"/>
#: system/settings/settings.xml
msgctxt "#346"
-msgid "Boost volume level on downmix"
+msgid "Normalize levels on downmix"
msgstr ""
#: system/settings/settings.xml
msgid "Same as movie"
msgstr ""
-#empty strings from id 36533 to 36534
+#: settings/DisplaySettings.cpp
+msgctxt "#36533"
+msgid "Select how audio is downmixed, for example from 5.1 to 2.0: [Enabled] maintains the dynamic range of the original audio source when downmixed however volume will be lower [Disabled] maintains volume level of the original audio source however the dynamic range is compressed. Note - Dynamic range is the difference between the quietest and loudest sounds in a audio source."
+msgstr ""
+
+#empty strings from id 36534 to 36534
#: guilib/StereoscopicsManager.cpp
#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp
</dependencies>
<control type="toggle" />
</setting>
+ <setting id="audiooutput.normalizelevels" type="boolean" label="346" help="36533">
+ <level>2</level>
+ <default>true</default>
+ </setting>
<setting id="audiooutput.processquality" type="integer" label="13505" help="36169">
<requirement>HAS_AE_QUALITY_LEVELS</requirement>
<level>2</level>
bool CApplication::ExecuteXBMCAction(std::string actionStr)
{
// see if it is a user set string
- CLog::Log(LOGDEBUG,"%s : Translating %s", __FUNCTION__, actionStr.c_str());
+
+ //We don't know if there is unsecure information in this yet, so we
+ //postpone any logging
+ const std::string in_actionStr(actionStr);
+ CLog::Log(LOGDEBUG,"%s : Translating action string", __FUNCTION__);
CGUIInfoLabel info(actionStr, "");
actionStr = info.GetLabel(0);
- CLog::Log(LOGDEBUG,"%s : To %s", __FUNCTION__, actionStr.c_str());
// user has asked for something to be executed
if (CBuiltins::HasCommand(actionStr))
PlayFile(item);
}
else
+ {
+ //At this point we have given up to translate, so even though
+ //there may be insecure information, we log it.
+ CLog::Log(LOGDEBUG,"%s : Tried translating, but failed to understand %s", __FUNCTION__, in_actionStr.c_str());
return false;
+ }
}
return true;
}
CFile file;
if (file.Open(GetDiscFileCache(windowID)))
{
- CLog::Log(LOGDEBUG,"Loading fileitems [%s]",GetPath().c_str());
CArchive ar(&file, CArchive::load);
ar >> *this;
- CLog::Log(LOGDEBUG," -- items: %i, directory: %s sort method: %i, ascending: %s", Size(), GetPath().c_str(), m_sortDescription.sortBy,
+ CLog::Log(LOGDEBUG,"Loading items: %i, directory: %s sort method: %i, ascending: %s", Size(), CURL::GetRedacted(GetPath()).c_str(), m_sortDescription.sortBy,
m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
ar.Close();
file.Close();
if (iSize <= 0)
return false;
- CLog::Log(LOGDEBUG,"Saving fileitems [%s]",GetPath().c_str());
+ CLog::Log(LOGDEBUG,"Saving fileitems [%s]", CURL::GetRedacted(GetPath()).c_str());
CFile file;
if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
void CGUIInfoManager::SetCurrentMovie(CFileItem &item)
{
- CLog::Log(LOGDEBUG,"CGUIInfoManager::SetCurrentMovie(%s)",item.GetPath().c_str());
+ CLog::Log(LOGDEBUG,"CGUIInfoManager::SetCurrentMovie(%s)", CURL::GetRedacted(item.GetPath()).c_str());
*m_currentFile = item;
/* also call GetMovieInfo() when a VideoInfoTag is already present or additional info won't be present in the tag */
strURL = GetWithoutFilename();
strURL += m_strFileName;
- if( m_strOptions.length() > 0 )
+ if( !m_strOptions.empty() )
strURL += m_strOptions;
- if (m_strProtocolOptions.length() > 0)
+ if (!m_strProtocolOptions.empty())
strURL += "|"+m_strProtocolOptions;
return strURL;
}
-CStdString CURL::GetWithoutUserDetails() const
+std::string CURL::GetWithoutUserDetails(bool redact) const
{
- CStdString strURL;
+ std::string strURL;
if (m_strProtocol.Equals("stack"))
{
CFileItemList items;
- CStdString strURL2;
+ std::string strURL2;
strURL2 = Get();
XFILE::CStackDirectory dir;
dir.GetDirectory(strURL2,items);
- vector<CStdString> newItems;
+ vector<std::string> newItems;
for (int i=0;i<items.Size();++i)
{
CURL url(items[i]->GetPath());
- items[i]->SetPath(url.GetWithoutUserDetails());
+ items[i]->SetPath(url.GetWithoutUserDetails(redact));
newItems.push_back(items[i]->GetPath());
}
- dir.ConstructStackPath(newItems,strURL);
+ dir.ConstructStackPath(newItems, strURL);
return strURL;
}
+ m_strProtocolOptions.length()
+ 10;
+ if (redact)
+ sizeneed += sizeof("USERNAME:PASSWORD@");
+
strURL.reserve(sizeneed);
if (m_strProtocol == "")
strURL = m_strProtocol;
strURL += "://";
- if (m_strHostName != "")
+ if (redact && !m_strUserName.empty())
+ {
+ strURL += "USERNAME";
+ if (!m_strPassword.empty())
+ {
+ strURL += ":PASSWORD";
+ }
+ strURL += "@";
+ }
+
+ if (!m_strHostName.empty())
{
- CStdString strHostName;
+ std::string strHostName;
if (URIUtils::ProtocolHasParentInHostname(m_strProtocol))
strHostName = CURL(m_strHostName).GetWithoutUserDetails();
if ( HasPort() )
{
- CStdString strPort;
- strPort.Format("%i", m_iPort);
- strURL += ":";
- strURL += strPort;
+ strURL += StringUtils::Format(":%i", m_iPort);
}
strURL += "/";
}
return strURL;
}
+std::string CURL::GetRedacted() const
+{
+ return GetWithoutUserDetails(true);
+}
+
+std::string CURL::GetRedacted(const std::string& path)
+{
+ return CURL(path).GetRedacted();
+}
+
bool CURL::IsLocal() const
{
return (IsLocalHost() || m_strProtocol.IsEmpty());
char GetDirectorySeparator() const;
CStdString Get() const;
- CStdString GetWithoutUserDetails() const;
+ std::string GetWithoutUserDetails(bool redact = false) const;
CStdString GetWithoutFilename() const;
+ std::string GetRedacted() const;
+ static std::string GetRedacted(const std::string& path);
bool IsLocal() const;
bool IsLocalHost() const;
static bool IsFileOnly(const CStdString &url); ///< return true if there are no directories in the url.
{
(*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
(*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
- (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix);
+ (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
}
if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
(*it)->m_resampleBuffers->m_fillPackets = true;
std::list<CActiveAEStream*>::iterator it;
for(it=m_streams.begin(); it!=m_streams.end(); ++it)
{
+ bool normalize = true;
+ if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
+ (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
+ !m_settings.normalizelevels)
+ normalize = false;
+
if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
(((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
- ((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)))
+ (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
+ ((*it)->m_resampleBuffers->m_normalize != normalize)))
{
(*it)->m_resampleBuffers->m_changeResampler = true;
}
(*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
(*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
+ (*it)->m_resampleBuffers->m_normalize = normalize;
}
}
fadingStep = delta / samples;
}
- // for stream amplification we need to run on a per sample basis
- if ((*it)->m_amplify != 1.0)
+ // for streams amplification of turned off downmix normalization
+ // we need to run on a per sample basis
+ if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
{
nb_floats = out->pkt->config.channels / out->pkt->planes;
nb_loops = out->pkt->nb_samples;
fadingStep = delta / samples;
}
- // for stream amplification we need to run on a per sample basis
- if ((*it)->m_amplify != 1.0)
+ // for streams amplification of turned off downmix normalization
+ // we need to run on a per sample basis
+ if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
{
nb_floats = out->pkt->config.channels / out->pkt->planes;
nb_loops = out->pkt->nb_samples;
m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
m_settings.stereoupmix = CSettings::Get().GetBool("audiooutput.stereoupmix");
+ m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
setting == "audiooutput.streamsilence" ||
setting == "audiooutput.processquality" ||
setting == "audiooutput.passthrough" ||
- setting == "audiooutput.samplerate")
+ setting == "audiooutput.samplerate" ||
+ setting == "audiooutput.normalizelevels")
{
m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
}
orig_config.fmt,
orig_config.bits_per_sample,
false,
+ true,
NULL,
AE_QUALITY_MID);
bool truehdpassthrough;
bool dtshdpassthrough;
bool stereoupmix;
+ bool normalizelevels;
bool passthrough;
int config;
unsigned int samplerate;
m_resampleQuality = quality;
m_changeResampler = false;
m_stereoUpmix = false;
+ m_normalize = true;
}
CActiveAEBufferPoolResample::~CActiveAEBufferPoolResample()
delete m_resampler;
}
-bool CActiveAEBufferPoolResample::Create(unsigned int totaltime, bool remap, bool upmix)
+bool CActiveAEBufferPoolResample::Create(unsigned int totaltime, bool remap, bool upmix, bool normalize)
{
CActiveAEBufferPool::Create(totaltime);
+ m_stereoUpmix = upmix;
+ m_normalize = true;
+ if ((m_format.m_channelLayout.Count() < m_inputFormat.m_channelLayout.Count() && !normalize))
+ m_normalize = false;
+
if (m_inputFormat.m_channelLayout != m_format.m_channelLayout ||
m_inputFormat.m_sampleRate != m_format.m_sampleRate ||
m_inputFormat.m_dataFormat != m_format.m_dataFormat ||
CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
upmix,
+ m_normalize,
remap ? &m_format.m_channelLayout : NULL,
m_resampleQuality);
}
- m_stereoUpmix = upmix;
m_changeResampler = false;
return true;
CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
m_stereoUpmix,
+ m_normalize,
NULL,
m_resampleQuality);
public:
CActiveAEBufferPoolResample(AEAudioFormat inputFormat, AEAudioFormat outputFormat, AEQuality quality);
virtual ~CActiveAEBufferPoolResample();
- virtual bool Create(unsigned int totaltime, bool remap, bool upmix);
+ virtual bool Create(unsigned int totaltime, bool remap, bool upmix, bool normalize = true);
void ChangeResampler();
bool ResampleBuffers(unsigned int timestamp = 0);
float GetDelay();
double m_resampleRatio;
AEQuality m_resampleQuality;
bool m_stereoUpmix;
+ bool m_normalize;
};
}
m_dllSwResample.Unload();
}
-bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, CAEChannelInfo *remapLayout, AEQuality quality)
+bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
{
if (!m_dllAvUtil.Load() || !m_dllSwResample.Load())
return false;
// not required for sink stage (remapLayout == true)
if ((m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP) &&
(m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP) &&
- !remapLayout)
+ !remapLayout && normalize)
{
m_dllAvUtil.av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
}
public:
CActiveAEResample();
virtual ~CActiveAEResample();
- bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, CAEChannelInfo *remapLayout, AEQuality quality);
+ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
int64_t GetDelay(int64_t base);
int GetBufferedSamples();
normalize = true;
else
{
- //FIXME: guisetting is reversed, change the setting name after frodo
- normalize = !CSettings::Get().GetBool("audiooutput.normalizelevels");
+ normalize = CSettings::Get().GetBool("audiooutput.normalizelevels");
CLog::Log(LOGDEBUG, "AERemap: Downmix normalization is %s", (normalize ? "enabled" : "disabled"));
}
}
if (result < 0 && m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0 )
{
- CLog::Log(LOGDEBUG, "Error, could not open file %s", strFile.c_str());
+ CLog::Log(LOGDEBUG, "Error, could not open file %s", CURL::GetRedacted(strFile).c_str());
Dispose();
m_dllAvUtil.av_dict_free(&options);
return false;
pd.buf_size = m_dllAvFormat.avio_read(m_ioContext, pd.buf, m_ioContext->max_packet_size ? m_ioContext->max_packet_size : m_ioContext->buffer_size);
if (pd.buf_size <= 0)
{
- CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, strFile.c_str());
+ CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
return false;
}
memset(pd.buf+pd.buf_size, 0, AVPROBE_PADDING_SIZE);
if (!iformat)
{
- CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, strFile.c_str());
+ CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
return false;
}
else
if (m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, NULL) < 0)
{
- CLog::Log(LOGERROR, "%s - Error, could not open file %s", __FUNCTION__, strFile.c_str());
+ CLog::Log(LOGERROR, "%s - Error, could not open file %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
Dispose();
return false;
}
int iErr = m_dllAvFormat.avformat_find_stream_info(m_pFormatContext, NULL);
if (iErr < 0)
{
- CLog::Log(LOGWARNING,"could not find codec parameters for %s", strFile.c_str());
+ CLog::Log(LOGWARNING,"could not find codec parameters for %s", CURL::GetRedacted(strFile).c_str());
if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)
|| m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY)
|| (m_pFormatContext->nb_streams == 1 && m_pFormatContext->streams[0]->codec->codec_id == AV_CODEC_ID_AC3))
bool CDVDFileInfo::ExtractThumb(const CStdString &strPath, CTextureDetails &details, CStreamDetails *pStreamDetails)
{
+ std::string redactPath = CURL::GetRedacted(strPath);
unsigned int nTime = XbmcThreads::SystemClockMillis();
CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strPath, "");
if (!pInputStream)
{
- CLog::Log(LOGERROR, "InputStream: Error creating stream for %s", strPath.c_str());
+ CLog::Log(LOGERROR, "InputStream: Error creating stream for %s", redactPath.c_str());
return false;
}
if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
{
- CLog::Log(LOGERROR, "InputStream: dvd streams not supported for thumb extraction, file: %s", strPath.c_str());
+ CLog::Log(LOGERROR, "InputStream: dvd streams not supported for thumb extraction, file: %s", redactPath.c_str());
delete pInputStream;
return false;
}
if (!pInputStream->Open(strPath.c_str(), ""))
{
- CLog::Log(LOGERROR, "InputStream: Error opening, %s", strPath.c_str());
+ CLog::Log(LOGERROR, "InputStream: Error opening, %s", redactPath.c_str());
if (pInputStream)
delete pInputStream;
return false;
int nTotalLen = pDemuxer->GetStreamLength();
int nSeekTo = nTotalLen / 3;
- CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, strPath.c_str());
+ CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str());
if (pDemuxer->SeekTime(nSeekTo, true))
{
int iDecoderState = VC_ERROR;
}
else
{
- CLog::Log(LOGDEBUG,"%s - decode failed in %s after %d packets.", __FUNCTION__, strPath.c_str(), packetsTried);
+ CLog::Log(LOGDEBUG,"%s - decode failed in %s after %d packets.", __FUNCTION__, redactPath.c_str(), packetsTried);
}
}
delete pVideoCodec;
}
unsigned int nTotalTime = XbmcThreads::SystemClockMillis() - nTime;
- CLog::Log(LOGDEBUG,"%s - measured %u ms to extract thumb from file <%s> in %d packets. ", __FUNCTION__, nTotalTime, strPath.c_str(), packetsTried);
+ CLog::Log(LOGDEBUG,"%s - measured %u ms to extract thumb from file <%s> in %d packets. ", __FUNCTION__, nTotalTime, redactPath.c_str(), packetsTried);
return bOk;
}
{
try
{
- CLog::Log(LOGNOTICE, "DVDPlayer: Opening: %s", file.GetPath().c_str());
+ CLog::Log(LOGNOTICE, "DVDPlayer: Opening: %s", CURL::GetRedacted(file.GetPath()).c_str());
// if playing a file close it first
// this has to be changed so we won't have to close it.
void COMXAudio::UpdateAttenuation()
{
+ // always called with m_critSection lock held
+ if (!m_Initialized || m_Passthrough)
+ return;
+
if (m_amplification == 1.0)
{
ApplyVolume();
#include "settings/Settings.h"
#include "linux/RBP.h"
#include "utils/URIUtils.h"
+#include "windowing/WindowingFactory.h"
+#include "Application.h"
+
+#ifdef _DEBUG
+#define CheckError() m_result = eglGetError(); if (m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
+#else
+#define CheckError()
+#endif
#define EXIF_TAG_ORIENTATION 0x0112
#endif
#define CLASSNAME "COMXImage"
+COMXImage::COMXImage()
+: CThread("CRBPWorker")
+{
+}
+
+COMXImage::~COMXImage()
+{
+ Deinitialize();
+}
+
+void COMXImage::Initialize()
+{
+ Create();
+}
+
+void COMXImage::Deinitialize()
+{
+ // wake up thread so it can quit
+ {
+ CSingleLock lock(m_texqueue_lock);
+ m_bStop = true;
+ m_texqueue_cond.notifyAll();
+ }
+ if (IsRunning())
+ StopThread();
+}
+
bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
unsigned int format, unsigned int pitch, const CStdString& destFile)
{
return okay;
}
+void COMXImage::AllocTextureInternal(struct textureinfo *tex)
+{
+ glGenTextures(1, (GLuint*) &tex->texture);
+ glBindTexture(GL_TEXTURE_2D, tex->texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
+ tex->egl_image = eglCreateImageKHR(m_egl_display, m_egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)tex->texture, NULL);
+ tex->sync.Set();
+ GLint m_result;
+ CheckError();
+}
+
+void COMXImage::GetTexture(void *userdata, GLuint *texture)
+{
+ struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
+ *texture = tex->texture;
+}
+
+void COMXImage::DestroyTextureInternal(struct textureinfo *tex)
+{
+ bool s = true;
+ if (!tex->egl_image || !tex->texture)
+ {
+ CLog::Log(LOGNOTICE, "%s: Invalid image/texture %p:%d", __func__, tex->egl_image, tex->texture);
+ return;
+ }
+ s = eglDestroyImageKHR(m_egl_display, tex->egl_image);
+ if (!s)
+ CLog::Log(LOGNOTICE, "%s: failed to destroy texture", __func__);
+ glDeleteTextures(1, (GLuint*) &tex->texture);
+ tex->sync.Set();
+}
+
+void COMXImage::DestroyTexture(void *userdata)
+{
+ struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
+ // we can only call gl functions from the application thread
+
+ tex->action = TEXTURE_DELETE;
+ tex->sync.Reset();
+ if ( g_application.IsCurrentThread() )
+ {
+ DestroyTextureInternal(tex);
+ }
+ else
+ {
+ CSingleLock lock(m_texqueue_lock);
+ m_texqueue.push(tex);
+ m_texqueue_cond.notifyAll();
+ }
+ // wait for function to have finished (in texture thread)
+ tex->sync.Wait();
+ delete tex;
+}
+
+bool COMXImage::DecodeJpegToTexture(COMXImageFile *file, unsigned int width, unsigned int height, void **userdata)
+{
+ bool ret = false;
+ COMXTexture omx_image;
+
+ struct textureinfo *tex = new struct textureinfo;
+ if (!tex)
+ return NULL;
+
+ tex->parent = (void *)this;
+ tex->width = width;
+ tex->height = height;
+ tex->texture = 0;
+ tex->egl_image = NULL;
+ tex->filename = file->GetFilename();
+ tex->action = TEXTURE_ALLOC;
+ tex->sync.Reset();
+
+ {
+ CSingleLock lock(m_texqueue_lock);
+ m_texqueue.push(tex);
+ m_texqueue_cond.notifyAll();
+ }
+
+ // wait for function to have finished (in texture thread)
+ tex->sync.Wait();
+
+ if (tex->egl_image && tex->texture && omx_image.Decode(file->GetImageBuffer(), file->GetImageSize(), width, height, tex->egl_image, m_egl_display))
+ {
+ ret = true;
+ *userdata = tex;
+ }
+ else
+ {
+ CLog::Log(LOGNOTICE, "%s: unable to decode to texture %s %dx%d", __func__, file->GetFilename(), width, height);
+ DestroyTexture(tex);
+ }
+ return ret;
+}
+
+static bool ChooseConfig(EGLDisplay display, const EGLint *configAttrs, EGLConfig *config)
+{
+ EGLBoolean eglStatus = true;
+ EGLint configCount = 0;
+ EGLConfig* configList = NULL;
+ GLint m_result;
+ // Find out how many configurations suit our needs
+ eglStatus = eglChooseConfig(display, configAttrs, NULL, 0, &configCount);
+ CheckError();
+
+ if (!eglStatus || !configCount)
+ {
+ CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %i", configCount);
+ return false;
+ }
+
+ // Allocate room for the list of matching configurations
+ configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
+ if (!configList)
+ {
+ CLog::Log(LOGERROR, "EGL failure obtaining configuration list");
+ return false;
+ }
+
+ // Obtain the configuration list from EGL
+ eglStatus = eglChooseConfig(display, configAttrs, configList, configCount, &configCount);
+ CheckError();
+ if (!eglStatus || !configCount)
+ {
+ CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d", eglStatus);
+ return false;
+ }
+
+ // Select an EGL configuration that matches the native window
+ *config = configList[0];
+
+ free(configList);
+ return true;
+}
+
+void COMXImage::CreateContext()
+{
+ EGLConfig egl_config;
+ GLint m_result;
+
+ m_egl_display = g_Windowing.GetEGLDisplay();
+ eglInitialize(m_egl_display, NULL, NULL);
+ CheckError();
+ eglBindAPI(EGL_OPENGL_ES_API);
+ CheckError();
+ static const EGLint contextAttrs [] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ static const EGLint configAttrs [] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 0,
+ EGL_SAMPLE_BUFFERS, 0,
+ EGL_SAMPLES, 0,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+ bool s = ChooseConfig(m_egl_display, configAttrs, &egl_config);
+ CheckError();
+ if (!s)
+ {
+ CLog::Log(LOGERROR, "%s: Could not find a compatible configuration",__FUNCTION__);
+ return;
+ }
+ m_egl_context = eglCreateContext(m_egl_display, egl_config, g_Windowing.GetEGLContext(), contextAttrs);
+ CheckError();
+ if (m_egl_context == EGL_NO_CONTEXT)
+ {
+ CLog::Log(LOGERROR, "%s: Could not create a context",__FUNCTION__);
+ return;
+ }
+ EGLSurface egl_surface = eglCreatePbufferSurface(m_egl_display, egl_config, NULL);
+ CheckError();
+ if (egl_surface == EGL_NO_SURFACE)
+ {
+ CLog::Log(LOGERROR, "%s: Could not create a surface",__FUNCTION__);
+ return;
+ }
+ s = eglMakeCurrent(m_egl_display, egl_surface, egl_surface, m_egl_context);
+ CheckError();
+ if (!s)
+ {
+ CLog::Log(LOGERROR, "%s: Could not make current",__FUNCTION__);
+ return;
+ }
+}
+
+void COMXImage::Process()
+{
+ bool firsttime = true;
+
+ while(!m_bStop)
+ {
+ struct textureinfo *tex = NULL;
+ while (!m_bStop)
+ {
+ CSingleLock lock(m_texqueue_lock);
+ if (!m_texqueue.empty())
+ {
+ tex = m_texqueue.front();
+ m_texqueue.pop();
+ break;
+ }
+ m_texqueue_cond.wait(lock);
+ }
+
+ if (m_bStop)
+ return;
+
+ if (firsttime)
+ CreateContext();
+ firsttime = false;
+
+ if (tex && tex->action == TEXTURE_ALLOC)
+ AllocTextureInternal(tex);
+ else if (tex && tex->action == TEXTURE_DELETE)
+ DestroyTextureInternal(tex);
+ else
+ CLog::Log(LOGERROR, "%s: Unexpected texture job: %p:%d", __func__, tex, tex ? tex->action : 0);
+ }
+}
+
+void COMXImage::OnStartup()
+{
+}
+
+void COMXImage::OnExit()
+{
+}
+
#ifdef CLASSNAME
#undef CLASSNAME
#endif
return true;
}
+
+
+#ifdef CLASSNAME
+#undef CLASSNAME
+#endif
+#define CLASSNAME "COMXTexture"
+
+COMXTexture::COMXTexture()
+{
+}
+
+COMXTexture::~COMXTexture()
+{
+ Close();
+}
+
+void COMXTexture::Close()
+{
+ CSingleLock lock(m_OMXSection);
+
+ if (m_omx_tunnel_decode.IsInitialized())
+ m_omx_tunnel_decode.Deestablish();
+ if (m_omx_tunnel_egl.IsInitialized())
+ m_omx_tunnel_egl.Deestablish();
+ // delete components
+ if (m_omx_decoder.IsInitialized())
+ m_omx_decoder.Deinitialize(true);
+ if (m_omx_resize.IsInitialized())
+ m_omx_resize.Deinitialize(true);
+ if (m_omx_egl_render.IsInitialized())
+ m_omx_egl_render.Deinitialize(true);
+}
+
+bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, void *egl_image, void *egl_display, bool port_settings_changed)
+{
+ OMX_ERRORTYPE omx_err;
+
+ if (port_settings_changed)
+ CLog::Log(LOGERROR, "%s::%s Unexpected second port_settings_changed call\n", CLASSNAME, __func__);
+
+ OMX_PARAM_PORTDEFINITIONTYPE port_def;
+ OMX_INIT_STRUCTURE(port_def);
+
+ port_def.nPortIndex = m_omx_decoder.GetOutputPort();
+ omx_err = 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.nStride = 0;
+
+ omx_err = 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", CLASSNAME, __func__);
+ return false;
+ }
+
+ port_def.nPortIndex = m_omx_resize.GetInputPort();
+
+ omx_err = 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();
+ omx_err = 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 = 16;
+ port_def.format.image.nStride = 0;
+ omx_err = 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_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit))
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
+ return false;
+ }
+
+ port_def.nPortIndex = m_omx_egl_render.GetOutputPort();
+ omx_err = m_omx_egl_render.GetParameter(OMX_IndexParamPortDefinition, &port_def);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+ port_def.nBufferCountActual = 1;
+ port_def.format.video.pNativeWindow = egl_display;
+
+ omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_def);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_egl_render.UseEGLImage(&m_egl_buffer, m_omx_egl_render.GetOutputPort(), NULL, egl_image);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.UseEGLImage (%x)", 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 (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
+
+ omx_err = m_omx_tunnel_egl.Establish(false);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ return true;
+}
+
+bool COMXTexture::Decode(const uint8_t *demuxer_content, unsigned demuxer_bytes, unsigned int width, unsigned int height, void *egl_image, void *egl_display)
+{
+ CSingleLock lock(m_OMXSection);
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if (!demuxer_content || !demuxer_bytes)
+ {
+ CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
+ return false;
+ }
+
+ if (!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__);
+ 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 error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, 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 error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_decoder.AllocInputBuffers();
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s - Error alloc buffers (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_sched.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ bool port_settings_changed = false;
+ bool 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 - m_omx_decoder.OMX_EmptyThisBuffer (%x)", CLASSNAME, __func__, 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(width, height, egl_image, egl_display, port_settings_changed))
+ {
+ CLog::Log(LOGERROR, "%s::%s - HandlePortSettingChange failed (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+ port_settings_changed = true;
+ }
+ else if (omx_err == OMX_ErrorStreamCorrupt)
+ {
+ CLog::Log(LOGERROR, "%s::%s - image not supported", CLASSNAME, __func__);
+ return false;
+ }
+ else if (timeout || omx_err != OMX_ErrorTimeout)
+ {
+ CLog::Log(LOGERROR, "%s::%s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ if (port_settings_changed && m_egl_buffer && demuxer_bytes == 0 && !eos)
+ {
+ OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_egl_render.GetOutputBuffer();
+ if (!omx_buffer)
+ {
+ CLog::Log(LOGERROR, "%s::%s GetOutputBuffer failed\n", CLASSNAME, __func__);
+ return false;
+ }
+ if (omx_buffer != m_egl_buffer)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetOutputBuffer (%p,%p)", CLASSNAME, __func__, omx_buffer, m_egl_buffer);
+ return false;
+ }
+
+ omx_err = m_omx_egl_render.FillThisBuffer(m_egl_buffer);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.FillThisBuffer (%x)", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+
+ omx_err = m_omx_egl_render.WaitForOutputDone(1000);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
+ return false;
+ }
+ eos = true;
+ }
+ }
+ Close();
+ return true;
+}
+
+COMXImage g_OMXImage;
#include "guilib/XBTF.h"
#endif
+#include "system_gl.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "threads/Thread.h"
+
using namespace XFILE;
using namespace std;
class COMXImageFile;
-class COMXImage
+class COMXImage : public CThread
{
+enum TextureAction {TEXTURE_ALLOC, TEXTURE_DELETE };
+
+struct textureinfo {
+ TextureAction action;
+ int width, height;
+ GLuint texture;
+ EGLImageKHR egl_image;
+ void *parent;
+ const char *filename;
+ CEvent sync;
+};
+
+protected:
+ virtual void OnStartup();
+ virtual void OnExit();
+ virtual void Process();
public:
+ COMXImage();
+ virtual ~COMXImage();
+ void Initialize();
+ void Deinitialize();
static COMXImageFile *LoadJpeg(const CStdString& texturePath);
static void CloseJpeg(COMXImageFile *file);
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);
+ bool DecodeJpegToTexture(COMXImageFile *file, unsigned int width, unsigned int height, void **userdata);
+ void DestroyTexture(void *userdata);
+ void GetTexture(void *userdata, GLuint *texture);
+private:
+ EGLDisplay m_egl_display;
+ EGLContext m_egl_context;
+
+ void CreateContext();
+ CCriticalSection m_texqueue_lock;
+ XbmcThreads::ConditionVariable m_texqueue_cond;
+ std::queue <struct textureinfo *> m_texqueue;
+ void AllocTextureInternal(struct textureinfo *tex);
+ void DestroyTextureInternal(struct textureinfo *tex);
};
class COMXImageFile
unsigned int m_nDestAllocSize;
};
+class COMXTexture
+{
+public:
+ COMXTexture();
+ virtual ~COMXTexture();
+
+ // Required overrides
+ void Close(void);
+ bool Decode(const uint8_t *data, unsigned size, unsigned int width, unsigned int height, void *egl_image, void *egl_display);
+protected:
+ bool HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, void *egl_image, void *egl_display, bool port_settings_changed);
+
+ // Components
+ COMXCoreComponent m_omx_decoder;
+ COMXCoreComponent m_omx_resize;
+ COMXCoreComponent m_omx_egl_render;
+
+ COMXCoreTunel m_omx_tunnel_decode;
+ COMXCoreTunel m_omx_tunnel_egl;
+
+ OMX_BUFFERHEADERTYPE *m_egl_buffer;
+ CCriticalSection m_OMXSection;
+};
+
+extern COMXImage g_OMXImage;
#endif
#endif
Create();
- if(!m_ready.WaitMSec(100))
+ if(!m_ready.WaitMSec(g_advancedSettings.m_videoBusyDialogDelay_ms))
{
CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY);
if(dialog)
{
CLog::Log(LOGDEBUG, "COMXPlayer::CloseFile");
- // unpause the player
- SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
-
// set the abort request so that other threads can finish up
m_bAbortRequest = true;
{
// check if we should read from subtitle demuxer
- if(m_dvdPlayerSubtitle.AcceptsData() && m_pSubtitleDemuxer)
+ if( m_pSubtitleDemuxer && m_dvdPlayerSubtitle.AcceptsData() )
{
- if(m_pSubtitleDemuxer)
- packet = m_pSubtitleDemuxer->Read();
+ packet = m_pSubtitleDemuxer->Read();
if(packet)
{
void COMXPlayer::SetSubtitle(int iStream)
{
+ CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = iStream;
m_messenger.Put(new CDVDMsgPlayerSetSubtitleStream(iStream));
}
void COMXPlayer::SetAudioStream(int iStream)
{
+ CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = iStream;
m_messenger.Put(new CDVDMsgPlayerSetAudioStream(iStream));
SynchronizeDemuxer(100);
}
/* software decoding normaly consumes full cpu time so prio it */
m_omxPlayerAudio.SetPriority(GetPriority()+1);
-
+ CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = m_SelectionStreams.IndexOf(STREAM_AUDIO, source, iStream);
return true;
}
m_CurrentSubtitle.stream = (void*)pStream;
m_CurrentSubtitle.started = false;
+ CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, source, iStream);
return true;
}
m_dvd.iDVDStillStartTime = XbmcThreads::SystemClockMillis();
/* adjust for the output delay in the video queue */
- DWORD time = 0;
+ unsigned int time = 0;
if( m_CurrentVideo.stream && m_dvd.iDVDStillTime > 0 )
{
- time = (DWORD)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
+ time = (unsigned int)(m_omxPlayerVideo.GetOutputDelay() / ( DVD_TIME_BASE / 1000 ));
if( time < 10000 && time > 0 )
m_dvd.iDVDStillTime += time;
}
break;
case DVDNAV_SPU_CLUT_CHANGE:
{
- m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((BYTE*)pData));
+ m_dvdPlayerSubtitle.SendMessage(new CDVDMsgSubtitleClutChange((uint8_t*)pData));
}
break;
case DVDNAV_SPU_STREAM_CHANGE:
THREAD_ACTION(action);
CLog::Log(LOGDEBUG, " - go to menu");
pMenus->OnMenu();
+ if (m_playSpeed == DVD_PLAYSPEED_PAUSE)
+ {
+ SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
+ m_callback.OnPlayBackResumed();
+ }
// send a message to everyone that we've gone to the menu
CGUIMessage msg(GUI_MSG_VIDEO_MENU_STARTED, 0, 0);
g_windowManager.SendThreadMessage(msg);
bool COMXPlayer::GetCurrentSubtitle(CStdString& strSubtitle)
{
- double pts = m_clock.GetClock();
+ double pts = m_clock.GetClock() + m_State.time_offset;
- if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
+ if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) && m_CurrentSubtitle.source != STREAM_SOURCE_TEXT && m_CurrentSubtitle.source != STREAM_SOURCE_DEMUX_SUB)
return false;
m_dvdPlayerSubtitle.GetCurrentSubtitle(strSubtitle, pts - m_omxPlayerVideo.GetSubtitleDelay());
double COMXPlayer::GetQueueTime()
{
- int a = m_omxPlayerVideo.GetLevel();
- int v = m_omxPlayerAudio.GetLevel();
+ int a = m_omxPlayerAudio.GetLevel();
+ int v = m_omxPlayerVideo.GetLevel();
return max(a, v) * 8000.0 / 100;
}
info.videoCodecName = retVal;
info.videoAspectRatio = g_renderManager.GetAspectRatio();
g_renderManager.GetVideoRect(info.SrcRect, info.DestRect);
- if (m_CurrentVideo.hint.stereo_mode == "mono")
+ info.stereoMode = m_omxPlayerVideo.GetStereoMode();
+ if (info.stereoMode == "mono")
info.stereoMode = "";
- else
- info.stereoMode = m_CurrentVideo.hint.stereo_mode;
}
int COMXPlayer::GetSourceBitrate()
int index = m_SelectionStreams.IndexOf(STREAM_SUBTITLE, m_SelectionStreams.Source(STREAM_SOURCE_DEMUX_SUB, filename), 0);
m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags;
m_SelectionStreams.Get(STREAM_SUBTITLE, index).filename2 = vobsubfile;
+ ExternalStreamInfo info;
+ CUtil::GetExternalStreamDetailsFromFilename(m_filename, vobsubfile, info);
+ m_SelectionStreams.Get(STREAM_SUBTITLE, index).name = info.name;
+ if (m_SelectionStreams.Get(STREAM_SUBTITLE, index).language.empty())
+ m_SelectionStreams.Get(STREAM_SUBTITLE, index).language = info.language;
+
+ if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE)
+ m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = flags;
+ else
+ m_SelectionStreams.Get(STREAM_SUBTITLE, index).flags = static_cast<CDemuxStream::EFlags>(info.flag);
+
return index;
}
if(ext == ".sub")
s.type = STREAM_SUBTITLE;
s.id = 0;
s.filename = filename;
- s.name = URIUtils::GetFileName(filename);
- s.flags = flags;
+ ExternalStreamInfo info;
+ CUtil::GetExternalStreamDetailsFromFilename(m_filename, filename, info);
+ s.name = info.name;
+ s.language = info.language;
+ if (static_cast<CDemuxStream::EFlags>(info.flag) == CDemuxStream::FLAG_NONE)
+ s .flags = flags;
+ else
+ s.flags = static_cast<CDemuxStream::EFlags>(info.flag);
+
m_SelectionStreams.Update(s);
return m_SelectionStreams.IndexOf(STREAM_SUBTITLE, s.source, s.id);
}
{
if (m_pDemuxer)
{
- bool result = CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, details);
+ std::vector<OMXSelectionStream> subs = m_SelectionStreams.Get(STREAM_SUBTITLE);
+ std::vector<CStreamDetailSubtitle> extSubDetails;
+ for (unsigned int i = 0; i < subs.size(); i++)
+ {
+ if (subs[i].filename == m_filename)
+ continue;
+
+ CStreamDetailSubtitle p;
+ p.m_strLanguage = subs[i].language;
+ extSubDetails.push_back(p);
+ }
+
+ bool result = CDVDFileInfo::DemuxerToStreamDetails(m_pInputStream, m_pDemuxer, extSubDetails, details);
if (result && details.GetStreamCount(CStreamDetail::VIDEO) > 0) // this is more correct (dvds in particular)
{
/*
}
}
+std::string OMXPlayerVideo::GetStereoMode()
+{
+ std::string stereo_mode;
+
+ switch(CMediaSettings::Get().GetCurrentVideoSettings().m_StereoMode)
+ {
+ case RENDER_STEREO_MODE_SPLIT_VERTICAL: stereo_mode = "left_right"; break;
+ case RENDER_STEREO_MODE_SPLIT_HORIZONTAL: stereo_mode = "top_bottom"; break;
+ default: stereo_mode = m_hints.stereo_mode; break;
+ }
+
+ if(CMediaSettings::Get().GetCurrentVideoSettings().m_StereoInvert)
+ stereo_mode = GetStereoModeInvert(stereo_mode);
+ return stereo_mode;
+}
+
void OMXPlayerVideo::Output(double pts, bool bDropPacket)
{
if (!g_renderManager.IsStarted()) {
void SetSpeed(int iSpeed);
std::string GetPlayerInfo();
int GetVideoBitrate();
+ std::string GetStereoMode();
double GetOutputDelay();
double GetSubtitleDelay() { return m_iSubtitleDelay; }
void SetSubtitleDelay(double delay) { m_iSubtitleDelay = delay; }
m_outStride = m_inSampleSize * m_outChannels;
/* see if we need to normalize the levels */
- bool dontnormalize = CSettings::Get().GetBool("audiooutput.normalizelevels");
+ bool dontnormalize = !CSettings::Get().GetBool("audiooutput.normalizelevels");
CLog::Log(LOGDEBUG, "CPCMRemap: Downmix normalization is %s", (dontnormalize ? "disabled" : "enabled"));
ResolveChannels();
{
CURL url(item.GetPath());
- CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers(%s)", item.GetPath().c_str());
+ CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers(%s)", CURL::GetRedacted(item.GetPath()).c_str());
// Process rules
for(unsigned int i = 0; i < m_vecCoreSelectionRules.size(); i++)
if (!m_rootDir.GetDirectory(strDirectory, items,m_useFileDirectories))
{
- CLog::Log(LOGERROR,"CGUIDialogFileBrowser::GetDirectory(%s) failed", strDirectory.c_str());
+ CLog::Log(LOGERROR,"CGUIDialogFileBrowser::GetDirectory(%s) failed", CURL::GetRedacted(strDirectory).c_str());
// We assume, we can get the parent
// directory again
// we was using url optons for urls, keep the old code work and warning
if (!url2.GetOptions().IsEmpty())
{
- CLog::Log(LOGWARNING, "%s: ftp url option is deprecated, please switch to use protocol option (change '?' to '|'), url: [%s]", __FUNCTION__, url2.Get().c_str());
+ CLog::Log(LOGWARNING, "%s: ftp url option is deprecated, please switch to use protocol option (change '?' to '|'), url: [%s]", __FUNCTION__, url2.GetRedacted().c_str());
url2.SetProtocolOptions(url2.GetOptions().Mid(1));
/* ftp has no options */
url2.SetOptions("");
CURL url2(url);
ParseAndCorrectUrl(url2);
- CLog::Log(LOGDEBUG, "CurlFile::Open(%p) %s", (void*)this, m_url.c_str());
+ std::string redactPath = CURL::GetRedacted(m_url);
+ CLog::Log(LOGDEBUG, "CurlFile::Open(%p) %s", (void*)this, redactPath.c_str());
ASSERT(!(!m_state->m_easyHandle ^ !m_state->m_multiHandle));
if( m_state->m_easyHandle == NULL )
|| !m_state->m_httpheader.GetValue("icy-name").empty()
|| !m_state->m_httpheader.GetValue("icy-br").empty()) && !m_skipshout)
{
- CLog::Log(LOGDEBUG,"CCurlFile::Open - File <%s> is a shoutcast stream. Re-opening", m_url.c_str());
+ CLog::Log(LOGDEBUG,"CCurlFile::Open - File <%s> is a shoutcast stream. Re-opening", redactPath.c_str());
throw new CRedirectException(new CShoutcastFile);
}
CURL url2(url);
ParseAndCorrectUrl(url2);
- CLog::Log(LOGDEBUG, "CCurlFile::OpenForWrite(%p) %s", (void*)this, m_url.c_str());
+ CLog::Log(LOGDEBUG, "CCurlFile::OpenForWrite(%p) %s", (void*)this, CURL::GetRedacted(m_url).c_str());
ASSERT(m_state->m_easyHandle == NULL);
g_curlInterface.easy_aquire(url2.GetProtocol(), url2.GetHostName(), &m_state->m_easyHandle, &m_state->m_multiHandle);
{
long code;
if(g_curlInterface.easy_getinfo(m_state->m_easyHandle, CURLINFO_RESPONSE_CODE, &code) == CURLE_OK )
- CLog::Log(LOGERROR, "%s - Unable to write curl resource (%s) - %ld", __FUNCTION__, m_url.c_str(), code);
+ CLog::Log(LOGERROR, "%s - Unable to write curl resource (%s) - %ld", __FUNCTION__, CURL::GetRedacted(m_url).c_str(), code);
m_inError = true;
return -1;
}
// if file is already running, get info from it
if( m_opened )
{
- CLog::Log(LOGWARNING, "CCurlFile::Exists - Exist called on open file %s", url.Get().c_str());
+ CLog::Log(LOGWARNING, "CCurlFile::Exists - Exist called on open file %s", url.GetRedacted().c_str());
return true;
}
{
long code;
if(g_curlInterface.easy_getinfo(m_state->m_easyHandle, CURLINFO_RESPONSE_CODE, &code) == CURLE_OK && code != 404 )
- CLog::Log(LOGERROR, "CCurlFile::Exists - Failed: HTTP returned error %ld for %s", code, url.Get().c_str());
+ CLog::Log(LOGERROR, "CCurlFile::Exists - Failed: HTTP returned error %ld for %s", code, url.GetRedacted().c_str());
}
else if (result != CURLE_REMOTE_FILE_NOT_FOUND && result != CURLE_FTP_COULDNT_RETR_FILE)
{
- CLog::Log(LOGERROR, "CCurlFile::Exists - Failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.Get().c_str());
+ CLog::Log(LOGERROR, "CCurlFile::Exists - Failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.GetRedacted().c_str());
}
errno = ENOENT;
// if file is already running, get info from it
if( m_opened )
{
- CLog::Log(LOGWARNING, "CCurlFile::Stat - Stat called on open file %s", url.Get().c_str());
+ CLog::Log(LOGWARNING, "CCurlFile::Stat - Stat called on open file %s", url.GetRedacted().c_str());
if (buffer)
{
memset(buffer, 0, sizeof(struct __stat64));
{
g_curlInterface.easy_release(&m_state->m_easyHandle, NULL);
errno = ENOENT;
- CLog::Log(LOGERROR, "CCurlFile::Stat - Failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.Get().c_str());
+ CLog::Log(LOGERROR, "CCurlFile::Stat - Failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.GetRedacted().c_str());
return -1;
}
if (url.GetProtocol() == "ftp")
{
g_curlInterface.easy_release(&m_state->m_easyHandle, NULL);
- CLog::Log(LOGNOTICE, "CCurlFile::Stat - Content length failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.Get().c_str());
+ CLog::Log(LOGNOTICE, "CCurlFile::Stat - Content length failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.GetRedacted().c_str());
errno = ENOENT;
return -1;
}
result = g_curlInterface.easy_getinfo(m_state->m_easyHandle, CURLINFO_CONTENT_TYPE, &content);
if (result != CURLE_OK)
{
- CLog::Log(LOGNOTICE, "CCurlFile::Stat - Content type failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.Get().c_str());
+ CLog::Log(LOGNOTICE, "CCurlFile::Stat - Content type failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.GetRedacted().c_str());
g_curlInterface.easy_release(&m_state->m_easyHandle, NULL);
errno = ENOENT;
return -1;
result = g_curlInterface.easy_getinfo(m_state->m_easyHandle, CURLINFO_FILETIME, &filetime);
if (result != CURLE_OK)
{
- CLog::Log(LOGNOTICE, "CCurlFile::Stat - Filetime failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.Get().c_str());
+ CLog::Log(LOGNOTICE, "CCurlFile::Stat - Filetime failed: %s(%d) for %s", g_curlInterface.easy_strerror(result), result, url.GetRedacted().c_str());
}
else
{
}
catch(...)
{
- CLog::Log(LOGERROR, "%s - Exception thrown while trying to retrieve header url: %s", __FUNCTION__, url.Get().c_str());
+ CLog::Log(LOGERROR, "%s - Exception thrown while trying to retrieve header url: %s", __FUNCTION__, url.GetRedacted().c_str());
return false;
}
}
file.SetUserAgent(useragent);
struct __stat64 buffer;
+ std::string redactUrl = url.GetRedacted();
if( file.Stat(url, &buffer) == 0 )
{
if (buffer.st_mode == _S_IFDIR)
content = "x-directory/normal";
else
content = file.GetMimeType();
- CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> %s", url.Get().c_str(), content.c_str());
+ CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> %s", redactUrl.c_str(), content.c_str());
return true;
}
- CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> failed", url.Get().c_str());
+ CLog::Log(LOGDEBUG, "CCurlFile::GetMimeType - %s -> failed", redactUrl.c_str());
content = "";
return false;
}
if (!dav.Open(url))
{
- CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
if (!davResponse.Parse(strResponse))
{
- CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
dav.Close();
return false;
}
if (!dav.Execute(url))
{
- CLog::Log(LOGERROR, "%s - Unable to create dav directory (%s) - %d", __FUNCTION__, url.Get().c_str(), dav.GetLastResponseCode());
+ CLog::Log(LOGERROR, "%s - Unable to create dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());
return false;
}
if (!dav.Execute(url))
{
- CLog::Log(LOGERROR, "%s - Unable to delete dav directory (%s) - %d", __FUNCTION__, url.Get().c_str(), dav.GetLastResponseCode());
+ CLog::Log(LOGERROR, "%s - Unable to delete dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());
return false;
}
#include "dialogs/GUIDialogBusy.h"
#include "threads/SingleLock.h"
#include "utils/URIUtils.h"
+#include "URL.h"
using namespace std;
using namespace XFILE;
{
if (!cancel && g_application.IsCurrentThread() && pDirectory->ProcessRequirements())
continue;
- CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
}
{
CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
}
- CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
{
CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
}
- CLog::Log(LOGERROR, "%s - Error creating %s", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Error creating %s", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
{
CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
}
- CLog::Log(LOGERROR, "%s - Error checking for %s", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Error checking for %s", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
{
CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
}
- CLog::Log(LOGERROR, "%s - Error removing %s", __FUNCTION__, strPath.c_str());
+ CLog::Log(LOGERROR, "%s - Error removing %s", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
return false;
}
int CFile::Stat(struct __stat64 *buffer)
{
+ if (!buffer)
+ return -1;
+
+ if (!m_pFile)
+ {
+ memset(buffer, 0, sizeof(struct __stat64));
+ errno = ENOENT;
+ return -1;
+ }
+
return m_pFile->Stat(buffer);
}
int CFile::Stat(const CStdString& strFileName, struct __stat64* buffer)
{
+ if (!buffer)
+ return -1;
+
CURL url;
try
unsigned int CFile::Read(void *lpBuf, int64_t uiBufSize)
{
- if (!m_pFile)
+ if (!m_pFile || !lpBuf)
return 0;
if(m_pBuffer)
//*********************************************************************************************
bool CFile::ReadString(char *szLine, int iLineLength)
{
- if (!m_pFile)
+ if (!m_pFile || !szLine)
return false;
if (m_pBuffer)
int CFile::Write(const void* lpBuf, int64_t uiBufSize)
{
+ if (!m_pFile || !lpBuf)
+ return -1;
+
try
{
return m_pFile->Write(lpBuf, uiBufSize);
// opening the source file.
if (!m_source.Open(m_sourcePath, READ_NO_CACHE | READ_TRUNCATED | READ_CHUNKED))
{
- CLog::Log(LOGERROR,"%s - failed to open source <%s>", __FUNCTION__, m_sourcePath.c_str());
+ CLog::Log(LOGERROR,"%s - failed to open source <%s>", __FUNCTION__, url.GetRedacted().c_str());
Close();
return false;
}
CStdString path;
XMLUtils::GetPath(node, "path", path);
if (!path.IsEmpty())
+ {
+ URIUtils::AddSlashAtEnd(path);
return CDirectory::GetDirectory(path, items, m_strFileMask, m_flags);
+ }
}
}
return false;
-
/*
* Copyright (C) 2005-2013 Team XBMC
* http://xbmc.org
if ((m_flags & DIR_FLAG_NO_FILE_INFO)==0 && g_advancedSettings.m_sambastatfiles)
{
// make sure we use the authenticated path wich contains any default username
- CStdString strFullName = strAuth + smb.URLEncode(strFile);
+ const CStdString strFullName = strAuth + smb.URLEncode(strFile);
lock.Enter();
hidden = true;
}
else
- CLog::Log(LOGERROR, "Getting extended attributes for the share: '%s'\nunix_err:'%x' error: '%s'", strFullName.c_str(), errno, strerror(errno));
+ CLog::Log(LOGERROR, "Getting extended attributes for the share: '%s'\nunix_err:'%x' error: '%s'", CURL::GetRedacted(strFullName).c_str(), errno, strerror(errno));
#endif
bIsDir = (info.st_mode & S_IFDIR) ? true : false;
iSize = info.st_size;
}
else
- CLog::Log(LOGERROR, "%s - Failed to stat file %s", __FUNCTION__, strFullName.c_str());
+ CLog::Log(LOGERROR, "%s - Failed to stat file %s", __FUNCTION__, CURL::GetRedacted(strFullName).c_str());
lock.Leave();
}
// remove the / or \ at the end. the samba library does not strip them off
// don't do this for smb:// !!
- CStdString s = strAuth;
+ std::string s = strAuth;
int len = s.length();
if (len > 1 && s.at(len - 2) != '/' &&
(s.at(len - 1) == '/' || s.at(len - 1) == '\\'))
s.erase(len - 1, 1);
}
- CLog::Log(LOGDEBUG, "%s - Using authentication url %s", __FUNCTION__, s.c_str());
+ CLog::Log(LOGDEBUG, "%s - Using authentication url %s", __FUNCTION__, CURL::GetRedacted(s).c_str());
{ CSingleLock lock(smb);
fd = smbc_opendir(s.c_str());
}
{
// write error to logfile
#ifdef TARGET_WINDOWS
- CLog::Log(LOGERROR, "SMBDirectory->GetDirectory: Unable to open directory : '%s'\nunix_err:'%x' nt_err : '%x' error : '%s'", strAuth.c_str(), errno, nt_error, get_friendly_nt_error_msg(nt_error));
+ CLog::Log(LOGERROR, "SMBDirectory->GetDirectory: Unable to open directory : '%s'\nunix_err:'%x' nt_err : '%x' error : '%s'", CURL::GetRedacted(strAuth).c_str(), errno, nt_error, get_friendly_nt_error_msg(nt_error));
#else
- CLog::Log(LOGERROR, "SMBDirectory->GetDirectory: Unable to open directory : '%s'\nunix_err:'%x' error : '%s'", strAuth.c_str(), errno, strerror(errno));
+ CLog::Log(LOGERROR, "SMBDirectory->GetDirectory: Unable to open directory : '%s'\nunix_err:'%x' error : '%s'", CURL::GetRedacted(strAuth).c_str(), errno, strerror(errno));
#endif
}
// write error to logfile
#ifdef TARGET_WINDOWS
int nt_error = smb.ConvertUnixToNT(errno);
- CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' nt_err : '%x' error : '%s'", strFileName.c_str(), errno, nt_error, get_friendly_nt_error_msg(nt_error));
+ CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' nt_err : '%x' error : '%s'", CURL::GetRedacted(strFileName).c_str(), errno, nt_error, get_friendly_nt_error_msg(nt_error));
#else
- CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' error : '%s'", strFileName.c_str(), errno, strerror(errno));
+ CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' error : '%s'", CURL::GetRedacted(strFileName).c_str(), errno, strerror(errno));
#endif
return false;
}
bool CStackDirectory::ConstructStackPath(const vector<CStdString> &paths, CStdString& stackedPath)
{
+ vector<string> pathsT;
+ pathsT.reserve(paths.size());
+ for (vector<CStdString>::const_iterator path = paths.begin();
+ path != paths.end(); ++path)
+ {
+ pathsT.push_back(*path);
+ }
+ std::string stackedPathT = stackedPath;
+ bool retVal = ConstructStackPath(pathsT, stackedPathT);
+ stackedPath = stackedPathT;
+ return retVal;
+ }
+
+ bool CStackDirectory::ConstructStackPath(const vector<std::string> &paths, std::string& stackedPath)
+ {
if (paths.size() < 2)
return false;
stackedPath = "stack://";
- CStdString folder, file;
+ std::string folder, file;
URIUtils::Split(paths[0], folder, file);
stackedPath += folder;
// double escape any occurence of commas
- file.Replace(",", ",,");
+ StringUtils::Replace(file, ",", ",,");
stackedPath += file;
for (unsigned int i = 1; i < paths.size(); ++i)
{
file = paths[i];
// double escape any occurence of commas
- file.Replace(",", ",,");
+ StringUtils::Replace(file, ",", ",,");
stackedPath += file;
}
return true;
static bool GetPaths(const CStdString& strPath, std::vector<CStdString>& vecPaths);
static CStdString ConstructStackPath(const CFileItemList& items, const std::vector<int> &stack);
static bool ConstructStackPath(const std::vector<CStdString> &paths, CStdString &stackedPath);
+ static bool ConstructStackPath(const std::vector<std::string> &paths, std::string &stackedPath);
};
}
m_constantNodes.insert("posx");
m_constantNodes.insert("posy");
+ m_constantNodes.insert("left");
+ m_constantNodes.insert("right");
+ m_constantNodes.insert("centerx");
+ m_constantNodes.insert("top");
+ m_constantNodes.insert("bottom");
+ m_constantNodes.insert("centery");
m_constantNodes.insert("width");
m_constantNodes.insert("height");
m_constantNodes.insert("offsetx");
{
XMLUtils::GetFloat(pChild, "posx", m_posX);
XMLUtils::GetFloat(pChild, "posy", m_posY);
+ XMLUtils::GetFloat(pChild, "left", m_posX);
+ XMLUtils::GetFloat(pChild, "top", m_posY);
TiXmlElement *originElement = pChild->FirstChildElement("origin");
while (originElement)
ifeq (@USE_OPENGLES@,1)
SRCS += TextureGL.cpp
+SRCS += TexturePi.cpp
SRCS += GUIFontTTFGL.cpp
SRCS += GUITextureGLES.cpp
SRCS += MatrixGLES.cpp
#include "rendering/RenderSystem.h"
#include "utils/log.h"
#include "utils/StringUtils.h"
+#include "URL.h"
#include "windowing/WindowingFactory.h"
if (stereoMode.empty())
stereoMode = "mono";
- CLog::Log(LOGDEBUG, "StereoscopicsManager: Detected stereo mode in string '%s' is '%s'", needle.c_str(), stereoMode.c_str());
+ CLog::Log(LOGDEBUG, "StereoscopicsManager: Detected stereo mode in string '%s' is '%s'", CURL::GetRedacted(needle).c_str(), stereoMode.c_str());
return stereoMode;
}
#include "filesystem/AndroidAppFile.h"
#endif
-#if defined(HAS_OMXPLAYER)
-#include "xbmc/cores/omxplayer/OMXImage.h"
-#endif
-
/************************************************************************/
/* */
/************************************************************************/
CLAMP(m_textureHeight, g_Windowing.GetMaxTextureSize());
CLAMP(m_imageWidth, m_textureWidth);
CLAMP(m_imageHeight, m_textureHeight);
+
delete[] m_pixels;
- m_pixels = new unsigned char[GetPitch() * GetRows()];
+ m_pixels = NULL;
+ if (GetPitch() * GetRows() > 0)
+ {
+ m_pixels = new unsigned char[GetPitch() * GetRows()];
+ }
}
void CBaseTexture::Update(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU)
bool CBaseTexture::LoadFromFileInternal(const CStdString& texturePath, unsigned int maxWidth, unsigned int maxHeight, bool autoRotate)
{
-#if defined(HAS_OMXPLAYER)
- if (URIUtils::HasExtension(texturePath, ".jpg|.tbn")
- /*|| URIUtils::HasExtension(texturePath, ".png")*/)
- {
- COMXImageFile *file = COMXImage::LoadJpeg(texturePath);
- if (file)
- {
- bool okay = false;
- int orientation = file->GetOrientation();
- // limit the sizes of jpegs (even if we fail to decode)
- COMXImage::ClampLimits(maxWidth, maxHeight, file->GetWidth(), file->GetHeight(), orientation & 4);
- Allocate(maxWidth, maxHeight, XB_FMT_A8R8G8B8);
- if (m_pixels && COMXImage::DecodeJpeg(file, maxWidth, GetRows(), GetPitch(), (void *)m_pixels))
- {
- m_hasAlpha = false;
- if (autoRotate && orientation)
- m_orientation = orientation - 1;
- okay = true;
- }
- COMXImage::CloseJpeg(file);
- if (okay)
- return true;
- }
- }
-#endif
if (URIUtils::HasExtension(texturePath, ".dds"))
{ // special case for DDS images
CDDSImage image;
class CTexture;
class CGLTexture;
+class CPiTexture;
class CDXTexture;
/*!
bool m_hasAlpha;
};
-#if defined(HAS_GL) || defined(HAS_GLES)
+#if defined(HAS_OMXPLAYER)
+#include "TexturePi.h"
+#define CTexture CPiTexture
+#elif defined(HAS_GL) || defined(HAS_GLES)
#include "TextureGL.h"
#define CTexture CGLTexture
#elif defined(HAS_DX)
*/
#include "system.h"
-#include "TextureGL.h"
+#include "Texture.h"
#include "windowing/WindowingFactory.h"
#include "utils/log.h"
#include "utils/GLUtils.h"
void LoadToGPU();
void BindToUnit(unsigned int unit);
-private:
+protected:
GLuint m_texture;
};
--- /dev/null
+/*
+ * Copyright (C) 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 "Texture.h"
+#include "windowing/WindowingFactory.h"
+#include "utils/log.h"
+#include "utils/GLUtils.h"
+#include "guilib/TextureManager.h"
+#include "utils/URIUtils.h"
+
+#if defined(HAS_OMXPLAYER)
+#include "cores/omxplayer/OMXImage.h"
+
+using namespace std;
+
+/************************************************************************/
+/* CPiTexture */
+/************************************************************************/
+
+CPiTexture::CPiTexture(unsigned int width, unsigned int height, unsigned int format)
+: CGLTexture(width, height, format)
+{
+ m_egl_image = NULL;
+}
+
+CPiTexture::~CPiTexture()
+{
+ if (m_egl_image)
+ {
+ g_OMXImage.DestroyTexture(m_egl_image);
+ m_egl_image = NULL;
+ }
+}
+
+void CPiTexture::Allocate(unsigned int width, unsigned int height, unsigned int format)
+{
+ if (m_egl_image)
+ {
+ m_imageWidth = m_originalWidth = width;
+ m_imageHeight = m_originalHeight = height;
+ m_format = format;
+ m_orientation = 0;
+
+ m_textureWidth = m_imageWidth;
+ m_textureHeight = m_imageHeight;
+ return;
+ }
+ return CGLTexture::Allocate(width, height, format);
+}
+
+void CPiTexture::CreateTextureObject()
+{
+ if (m_egl_image && !m_texture)
+ {
+ g_OMXImage.GetTexture(m_egl_image, &m_texture);
+ return;
+ }
+ CGLTexture::CreateTextureObject();
+}
+
+void CPiTexture::LoadToGPU()
+{
+ if (m_egl_image)
+ {
+ if (m_loadedToGPU)
+ {
+ // nothing to load - probably same image (no change)
+ return;
+ }
+ if (m_texture == 0)
+ {
+ // Have OpenGL generate a texture object handle for us
+ // this happens only one time - the first time the texture is loaded
+ CreateTextureObject();
+ }
+
+ // Bind the texture object
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+ m_loadedToGPU = true;
+ return;
+ }
+ CGLTexture::LoadToGPU();
+}
+
+void CPiTexture::Update(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU)
+{
+ if (m_egl_image)
+ {
+ if (loadToGPU)
+ LoadToGPU();
+ return;
+ }
+ CGLTexture::Update(width, height, pitch, format, pixels, loadToGPU);
+}
+
+bool CPiTexture::LoadFromFileInternal(const CStdString& texturePath, unsigned int maxWidth, unsigned int maxHeight, bool autoRotate)
+{
+ if (URIUtils::HasExtension(texturePath, ".jpg|.tbn"))
+ {
+ COMXImageFile *file = g_OMXImage.LoadJpeg(texturePath);
+ if (file)
+ {
+ bool okay = false;
+ int orientation = file->GetOrientation();
+ // limit the sizes of jpegs (even if we fail to decode)
+ g_OMXImage.ClampLimits(maxWidth, maxHeight, file->GetWidth(), file->GetHeight(), orientation & 4);
+ if (g_OMXImage.DecodeJpegToTexture(file, maxWidth, maxHeight, &m_egl_image) && m_egl_image)
+ {
+ m_hasAlpha = false;
+ if (autoRotate && orientation)
+ m_orientation = orientation - 1;
+ Allocate(maxWidth, maxHeight, XB_FMT_A8R8G8B8);
+ okay = true;
+ }
+ g_OMXImage.CloseJpeg(file);
+ if (okay)
+ return true;
+ }
+ }
+ return CGLTexture::LoadFromFileInternal(texturePath, maxWidth, maxHeight, autoRotate);
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 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/>.
+ *
+ */
+
+#pragma once
+
+#include "TextureGL.h"
+
+#if defined(HAS_OMXPLAYER)
+
+#include "system_gl.h"
+
+/************************************************************************/
+/* CGLTexture */
+/************************************************************************/
+class CPiTexture : public CGLTexture
+{
+public:
+ CPiTexture(unsigned int width = 0, unsigned int height = 0, unsigned int format = XB_FMT_A8R8G8B8);
+ virtual ~CPiTexture();
+ void CreateTextureObject();
+ void LoadToGPU();
+ void Update(unsigned int width, unsigned int height, unsigned int pitch, unsigned int format, const unsigned char *pixels, bool loadToGPU);
+ void Allocate(unsigned int width, unsigned int height, unsigned int format);
+ bool LoadFromFileInternal(const CStdString& texturePath, unsigned int maxWidth, unsigned int maxHeight, bool autoRotate);
+
+protected:
+
+private:
+ void *m_egl_image;
+};
+
+#endif
{ "VideoLibrary.GetRecentlyAddedEpisodes", CVideoLibrary::GetRecentlyAddedEpisodes },
{ "VideoLibrary.GetRecentlyAddedMusicVideos", CVideoLibrary::GetRecentlyAddedMusicVideos },
{ "VideoLibrary.SetMovieDetails", CVideoLibrary::SetMovieDetails },
+ { "VideoLibrary.SetMovieSetDetails", CVideoLibrary::SetMovieSetDetails },
{ "VideoLibrary.SetTVShowDetails", CVideoLibrary::SetTVShowDetails },
{ "VideoLibrary.SetSeasonDetails", CVideoLibrary::SetSeasonDetails },
{ "VideoLibrary.SetEpisodeDetails", CVideoLibrary::SetEpisodeDetails },
namespace JSONRPC
{
const char* const JSONRPC_SERVICE_ID = "http://xbmc.org/jsonrpc/ServiceDescription.json";
- const char* const JSONRPC_SERVICE_VERSION = "6.11.0";
+ const char* const JSONRPC_SERVICE_VERSION = "6.12.0";
const char* const JSONRPC_SERVICE_DESCRIPTION = "JSON-RPC API of XBMC";
const char* const JSONRPC_SERVICE_TYPES[] = {
"],"
"\"returns\": \"string\""
"}",
+ "\"VideoLibrary.SetMovieSetDetails\": {"
+ "\"type\": \"method\","
+ "\"description\": \"Update the given movie set with the given details\","
+ "\"transport\": \"Response\","
+ "\"permission\": \"UpdateData\","
+ "\"params\": ["
+ "{ \"name\": \"setid\", \"$ref\": \"Library.Id\", \"required\": true },"
+ "{ \"name\": \"title\", \"$ref\": \"Optional.String\" },"
+ "{ \"name\": \"art\", \"type\": [ \"null\", { \"$ref\": \"Media.Artwork.Set\", \"required\": true } ], \"default\": null }"
+ "],"
+ "\"returns\": \"string\""
+ "}",
"\"VideoLibrary.SetTVShowDetails\": {"
"\"type\": \"method\","
"\"description\": \"Update the given tvshow with the given details\","
return ACK;
}
+JSONRPC_STATUS CVideoLibrary::SetMovieSetDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
+{
+ int id = (int)parameterObject["setid"].asInteger();
+
+ CVideoDatabase videodatabase;
+ if (!videodatabase.Open())
+ return InternalError;
+
+ CVideoInfoTag infos;
+ videodatabase.GetSetInfo(id, infos);
+ if (infos.m_iDbId <= 0)
+ {
+ videodatabase.Close();
+ return InvalidParams;
+ }
+
+ // get artwork
+ std::map<std::string, std::string> artwork;
+ videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork);
+
+ std::set<std::string> removedArtwork;
+ UpdateVideoTag(parameterObject, infos, artwork, removedArtwork);
+
+ if (videodatabase.SetDetailsForMovieSet(infos, artwork, id) <= 0)
+ return InternalError;
+
+ if (!videodatabase.RemoveArtForItem(infos.m_iDbId, "set", removedArtwork))
+ return InternalError;
+
+ CJSONRPCUtils::NotifyItemUpdated();
+ return ACK;
+}
+
JSONRPC_STATUS CVideoLibrary::SetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
int id = (int)parameterObject["tvshowid"].asInteger();
static JSONRPC_STATUS GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
static JSONRPC_STATUS SetMovieDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
+ static JSONRPC_STATUS SetMovieSetDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
static JSONRPC_STATUS SetTVShowDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
static JSONRPC_STATUS SetSeasonDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
static JSONRPC_STATUS SetEpisodeDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result);
],
"returns": "string"
},
+ "VideoLibrary.SetMovieSetDetails": {
+ "type": "method",
+ "description": "Update the given movie set with the given details",
+ "transport": "Response",
+ "permission": "UpdateData",
+ "params": [
+ { "name": "setid", "$ref": "Library.Id", "required": true },
+ { "name": "title", "$ref": "Optional.String" },
+ { "name": "art", "type": [ "null", { "$ref": "Media.Artwork.Set", "required": true } ], "default": null }
+ ],
+ "returns": "string"
+ },
"VideoLibrary.SetTVShowDetails": {
"type": "method",
"description": "Update the given tvshow with the given details",
OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage)
{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
if(!m_handle)
return OMX_ErrorUndefined;
- OMX_ERRORTYPE omx_err;
+ m_omx_output_use_buffers = false;
- omx_err = OMX_UseEGLImage(m_handle, ppBufferHdr, nPortIndex, pAppPrivate, eglImage);
- if(omx_err != OMX_ErrorNone)
+ OMX_PARAM_PORTDEFINITIONTYPE portFormat;
+ OMX_INIT_STRUCTURE(portFormat);
+ portFormat.nPortIndex = m_output_port;
+
+ omx_err = OMX_GetParameter(m_handle, OMX_IndexParamPortDefinition, &portFormat);
+ if(omx_err != OMX_ErrorNone)
+ return omx_err;
+
+ if(GetState() != OMX_StateIdle)
{
- CLog::Log(LOGERROR, "COMXCoreComponent::UseEGLImage - %s failed with omx_err(0x%x)\n",
+ if(GetState() != OMX_StateLoaded)
+ SetStateForComponent(OMX_StateLoaded);
+
+ SetStateForComponent(OMX_StateIdle);
+ }
+
+ omx_err = EnablePort(m_output_port, false);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s - %s EnablePort failed with omx_err(0x%x)", CLASSNAME, __func__,
m_componentName.c_str(), omx_err);
+ return omx_err;
+ }
+
+ m_output_alignment = portFormat.nBufferAlignment;
+ m_output_buffer_count = portFormat.nBufferCountActual;
+ m_output_buffer_size = portFormat.nBufferSize;
+
+ if (portFormat.nBufferCountActual != 1)
+ {
+ CLog::Log(LOGERROR, "%s::%s - %s nBufferCountActual unexpected %d", CLASSNAME, __func__,
+ m_componentName.c_str(), portFormat.nBufferCountActual);
+ return omx_err;
+ }
+
+ CLog::Log(LOGDEBUG, "%s::%s component(%s) - port(%d), nBufferCountMin(%u), nBufferCountActual(%u), nBufferSize(%u) nBufferAlignmen(%u)\n",
+ CLASSNAME, __func__, m_componentName.c_str(), m_output_port, portFormat.nBufferCountMin,
+ portFormat.nBufferCountActual, portFormat.nBufferSize, portFormat.nBufferAlignment);
+
+ for (size_t i = 0; i < portFormat.nBufferCountActual; i++)
+ {
+ omx_err = OMX_UseEGLImage(m_handle, ppBufferHdr, nPortIndex, pAppPrivate, eglImage);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "%s::%s - %s failed with omx_err(0x%x)\n",
+ CLASSNAME, __func__, m_componentName.c_str(), omx_err);
+ return omx_err;
+ }
+
+ OMX_BUFFERHEADERTYPE *buffer = *ppBufferHdr;
+ buffer->nOutputPortIndex = m_output_port;
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->pAppPrivate = (void*)i;
+ m_omx_output_buffers.push_back(buffer);
+ m_omx_output_available.push(buffer);
}
+ omx_err = WaitForCommand(OMX_CommandPortEnable, m_output_port);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, " %s::%s - %s EnablePort failed with omx_err(0x%x)\n",
+ CLASSNAME, __func__, m_componentName.c_str(), omx_err);
+ return omx_err;
+ }
+ m_flush_output = false;
+
return omx_err;
}
#include "utils/log.h"
+#include "cores/omxplayer/OMXImage.h"
+
CRBP::CRBP()
{
m_initialized = false;
if (vc_gencmd(response, sizeof response, "get_mem gpu") == 0)
vc_gencmd_number_property(response, "gpu", &m_gpu_mem);
+ g_OMXImage.Initialize();
+ m_omx_image_init = true;
return true;
}
void CRBP::Deinitialize()
{
+ if (m_omx_image_init)
+ g_OMXImage.Deinitialize();
+
if(m_omx_initialized)
m_OMX->Deinitialize();
if(m_initialized)
m_DllBcmHost->Unload();
+ m_omx_image_init = false;
m_initialized = false;
m_omx_initialized = false;
}
DllBcmHost *m_DllBcmHost;
bool m_initialized;
bool m_omx_initialized;
+ bool m_omx_image_init;
int m_arm_mem;
int m_gpu_mem;
COMXCore *m_OMX;
return sProfilesManager;
}
-bool CProfilesManager::OnSettingsLoading()
-{
- return true;
-}
-
void CProfilesManager::OnSettingsLoaded()
{
// check them all
public:
static CProfilesManager& Get();
- virtual bool OnSettingsLoading();
virtual void OnSettingsLoaded();
virtual bool OnSettingsSaved();
virtual void OnSettingsCleared();
settingSet.insert("audiooutput.audiodevice");
settingSet.insert("audiooutput.passthroughdevice");
settingSet.insert("audiooutput.streamsilence");
+ settingSet.insert("audiooutput.normalizelevels");
settingSet.insert("lookandfeel.skin");
settingSet.insert("lookandfeel.skinsettings");
settingSet.insert("lookandfeel.font");
bool CSettingsManager::Load(const TiXmlElement *root, bool &updated, bool triggerEvents /* = true */, std::map<std::string, CSetting*> *loadedSettings /* = NULL */)
{
- CExclusiveLock lock(m_critical);
+ CSharedLock lock(m_critical);
CExclusiveLock settingsLock(m_settingsCritical);
if (m_loaded || root == NULL)
return false;
TestBasicEnvironment.cpp \
TestFileItem.cpp \
TestTextureCache.cpp \
+ TestURL.cpp \
TestUtils.cpp \
xbmc-test.cpp
--- /dev/null
+/*
+ * Copyright (C) 2005-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 "URL.h"
+
+#include "gtest/gtest.h"
+
+using ::testing::Test;
+using ::testing::WithParamInterface;
+using ::testing::ValuesIn;
+
+struct TestURLGetWithoutUserDetailsData
+{
+ std::string input;
+ std::string expected;
+ bool redact;
+};
+
+std::ostream& operator<<(std::ostream& os,
+ const TestURLGetWithoutUserDetailsData& rhs)
+{
+ return os << "(Input: " << rhs.input <<
+ "; Redact: " << (rhs.redact?"true":"false") <<
+ "; Expected: " << rhs.expected << ")";
+}
+
+class TestURLGetWithoutUserDetails : public Test,
+ public WithParamInterface<TestURLGetWithoutUserDetailsData>
+{
+};
+
+TEST_P(TestURLGetWithoutUserDetails, GetWithoutUserDetails)
+{
+ CURL input(GetParam().input);
+ std::string result = input.GetWithoutUserDetails(GetParam().redact);
+ EXPECT_EQ(result, GetParam().expected);
+}
+
+const TestURLGetWithoutUserDetailsData values[] = {
+ { std::string("smb://example.com/example"), std::string("smb://example.com/example"), false },
+ { std::string("smb://example.com/example"), std::string("smb://example.com/example"), true },
+ { std::string("smb://god:universe@example.com/example"), std::string("smb://example.com/example"), false },
+ { std::string("smb://god@example.com/example"), std::string("smb://USERNAME@example.com/example"), true },
+ { std::string("smb://god:universe@example.com/example"), std::string("smb://USERNAME:PASSWORD@example.com/example"), true },
+ { std::string("http://god:universe@example.com:8448/example|auth=digest"), std::string("http://USERNAME:PASSWORD@example.com:8448/example|auth=digest"), true }
+ };
+
+INSTANTIATE_TEST_CASE_P(URL, TestURLGetWithoutUserDetails, ValuesIn(values));
#endif
if (m_item.IsVideo())
{
- CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, progressTrackingFile.c_str());
+ std::string redactPath = CURL::GetRedacted(progressTrackingFile);
+ CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, redactPath.c_str());
CVideoDatabase videodatabase;
if (!videodatabase.Open())
{
if (m_updatePlayCount)
{
- CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, progressTrackingFile.c_str());
+ CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, redactPath.c_str());
// consider this item as played
videodatabase.IncrementPlayCount(m_item);
if (m_item.IsAudio())
{
- CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, m_item.GetPath().c_str());
+ std::string redactPath = CURL::GetRedacted(progressTrackingFile);
+ CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, redactPath.c_str());
if (m_updatePlayCount)
{
else
{
// consider this item as played
- CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, m_item.GetPath().c_str());
+ CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, redactPath.c_str());
musicdatabase.IncrementPlayCount(m_item);
musicdatabase.Close();
void URIUtils::Split(const CStdString& strFileNameAndPath,
CStdString& strPath, CStdString& strFileName)
{
+ std::string strPathT, strFileNameT;
+ Split(strFileNameAndPath, strPathT, strFileNameT);
+ strPath = strPathT;
+ strFileName = strFileNameT;
+}
+
+void URIUtils::Split(const std::string& strFileNameAndPath,
+ std::string& strPath, std::string& strFileName)
+{
//Splits a full filename in path and file.
//ex. smb://computer/share/directory/filename.ext -> strPath:smb://computer/share/directory/ and strFileName:filename.ext
//Trailing slash will be preserved
if (i == 0)
i--;
- strPath = strFileNameAndPath.Left(i + 1);
- strFileName = strFileNameAndPath.Right(strFileNameAndPath.size() - i - 1);
+ // take left including the directory separator
+ strPath = strFileNameAndPath.substr(0, i+1);
+ // everything to the right of the directory separator
+ strFileName = strFileNameAndPath.substr(i+1);
}
CStdStringArray URIUtils::SplitPath(const CStdString& strPath)
const CStdString& strNewExtension);
static void Split(const CStdString& strFileNameAndPath,
CStdString& strPath, CStdString& strFileName);
+ static void Split(const std::string& strFileNameAndPath,
+ std::string& strPath, std::string& strFileName);
static CStdStringArray SplitPath(const CStdString& strPath);
static void GetCommonPath(CStdString& strPath, const CStdString& strPath2);
else
strSQL=PrepareSQL("select idMovie from movie where idFile=%i", idFile);
- CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
+ CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, CURL::GetRedacted(strFilenameAndPath).c_str(), strSQL.c_str());
m_pDS->query(strSQL.c_str());
if (m_pDS->num_rows() > 0)
idMovie = m_pDS->fv("idMovie").get_asInt();
CStdString strSQL=PrepareSQL("select idEpisode from episode where idFile=%i", idFile);
- CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
+ CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, CURL::GetRedacted(strFilenameAndPath).c_str(), strSQL.c_str());
pDS->query(strSQL.c_str());
if (pDS->num_rows() > 0)
{
CStdString strSQL=PrepareSQL("select idMVideo from musicvideo where idFile=%i", idFile);
- CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, strFilenameAndPath.c_str(), strSQL.c_str());
+ CLog::Log(LOGDEBUG, "%s (%s), query = %s", __FUNCTION__, CURL::GetRedacted(strFilenameAndPath).c_str(), strSQL.c_str());
m_pDS->query(strSQL.c_str());
int idMVideo=-1;
if (m_pDS->num_rows() > 0)
CStdString strSQL=PrepareSQL("insert into movie (idMovie, idFile) values (NULL, %i)", idFile);
m_pDS->exec(strSQL.c_str());
idMovie = (int)m_pDS->lastinsertid();
-// CommitTransaction();
}
return idMovie;
strSQL=PrepareSQL("insert into tvshowlinkpath values (%i,%i)",idTvShow,idPath);
m_pDS->exec(strSQL.c_str());
-// CommitTransaction();
-
return idTvShow;
}
catch (...)
// query DB for any movies matching imdbid and year
CStdString strSQL = PrepareSQL("select files.playCount, files.lastPlayed from movie,files where files.idFile=movie.idFile and movie.c%02d='%s' and movie.c%02d=%i and movie.idMovie!=%i and files.playCount > 0", VIDEODB_ID_IDENT, details.m_strIMDBNumber.c_str(), VIDEODB_ID_YEAR, details.m_iYear, idMovie);
m_pDS->query(strSQL.c_str());
-
+
if (!m_pDS->eof())
{
int playCount = m_pDS->fv("files.playCount").get_asInt();
return -1;
}
+int CVideoDatabase::SetDetailsForMovieSet(const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, int idSet /* = -1 */)
+{
+ if (details.m_strTitle.empty())
+ return -1;
+
+ try
+ {
+ BeginTransaction();
+ if (idSet < 0)
+ {
+ idSet = AddSet(details.m_strTitle);
+ if (idSet < 0)
+ {
+ RollbackTransaction();
+ return -1;
+ }
+ }
+
+ SetArtForItem(idSet, "set", artwork);
+
+ // and insert the new row
+ CStdString sql = PrepareSQL("UPDATE sets SET strSet='%s' WHERE idSet=%i", details.m_strTitle.c_str(), idSet);
+ m_pDS->exec(sql.c_str());
+ CommitTransaction();
+
+ return idSet;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s (%i) failed", __FUNCTION__, idSet);
+ }
+ RollbackTransaction();
+ return -1;
+}
+
int CVideoDatabase::SetDetailsForTvShow(const CStdString& strPath, const CVideoInfoTag& details, const map<string, string> &artwork, const map<int, map<string, string> > &seasonArt, int idTvShow /*= -1 */)
{
try
void GetEpisodesByFile(const CStdString& strFilenameAndPath, std::vector<CVideoInfoTag>& episodes);
int SetDetailsForMovie(const CStdString& strFilenameAndPath, const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, int idMovie = -1);
+ int SetDetailsForMovieSet(const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, int idSet = -1);
int SetDetailsForTvShow(const CStdString& strPath, const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, const std::map<int, std::map<std::string, std::string> > &seasonArt, int idTvShow = -1);
int SetDetailsForSeason(const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, int idShow, int idSeason = -1);
int SetDetailsForEpisode(const CStdString& strFilenameAndPath, const CVideoInfoTag& details, const std::map<std::string, std::string> &artwork, int idShow, int idEpisode=-1);
CStdString fastHash = GetFastHash(strDirectory);
if (m_database.GetPathHash(strDirectory, dbHash) && !fastHash.IsEmpty() && fastHash == dbHash)
{ // fast hashes match - no need to process anything
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' due to no change (fasthash)", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' due to no change (fasthash)", CURL::GetRedacted(strDirectory).c_str());
hash = fastHash;
bSkip = true;
}
if (hash != dbHash && !hash.IsEmpty())
{
if (dbHash.IsEmpty())
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Scanning dir '%s' as not in the database", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Scanning dir '%s' as not in the database", CURL::GetRedacted(strDirectory).c_str());
else
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Rescanning dir '%s' due to change (%s != %s)", strDirectory.c_str(), dbHash.c_str(), hash.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Rescanning dir '%s' due to change (%s != %s)", CURL::GetRedacted(strDirectory).c_str(), dbHash.c_str(), hash.c_str());
}
else
{ // they're the same or the hash is empty (dir empty/dir not retrievable)
if (hash.IsEmpty() && !dbHash.IsEmpty())
{
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' as it's empty or doesn't exist - adding to clean list", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' as it's empty or doesn't exist - adding to clean list", CURL::GetRedacted(strDirectory).c_str());
m_pathsToClean.insert(m_database.GetPathId(strDirectory));
}
else
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' due to no change", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Skipping dir '%s' due to no change", CURL::GetRedacted(strDirectory).c_str());
bSkip = true;
if (m_handle)
OnDirectoryScanned(strDirectory);
{
m_database.SetPathHash(strDirectory, hash);
m_pathsToClean.insert(m_database.GetPathId(strDirectory));
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Finished adding information from dir %s", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Finished adding information from dir %s", CURL::GetRedacted(strDirectory).c_str());
}
}
else
{
m_pathsToClean.insert(m_database.GetPathId(strDirectory));
- CLog::Log(LOGDEBUG, "VideoInfoScanner: No (new) information was found in dir %s", strDirectory.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: No (new) information was found in dir %s", CURL::GetRedacted(strDirectory).c_str());
}
}
else if (hash != dbHash && (content == CONTENT_MOVIES || content == CONTENT_MUSICVIDEOS))
ret = RetrieveInfoForMusicVideo(pItem.get(), bDirNames, info2, useLocal, pURL, pDlgProgress);
else
{
- CLog::Log(LOGERROR, "VideoInfoScanner: Unknown content type %d (%s)", info2->Content(), pItem->GetPath().c_str());
+ CLog::Log(LOGERROR, "VideoInfoScanner: Unknown content type %d (%s)", info2->Content(), CURL::GetRedacted(pItem->GetPath()).c_str());
FoundSomeInfo = false;
break;
}
if (ret == INFO_ADDED || ret == INFO_HAVE_ALREADY)
FoundSomeInfo = true;
else if (ret == INFO_NOT_FOUND)
- CLog::Log(LOGWARNING, "No information found for item '%s', it won't be added to the library.", pItem->GetPath().c_str());
+ {
+ CLog::Log(LOGWARNING, "No information found for item '%s', it won't be added to the library.", CURL::GetRedacted(pItem->GetPath()).c_str());
+ }
pURL = NULL;
{
CStdString decode(items[i]->GetPath());
CURL::Decode(decode);
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Could not enumerate file %s", decode.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Could not enumerate file %s", CURL::GetRedacted(decode).c_str());
}
}
}
strTitle.Format("%s - %ix%i - %s", showInfo->m_strTitle.c_str(), movieDetails.m_iSeason, movieDetails.m_iEpisode, strTitle.c_str());
}
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Adding new item to %s:%s", TranslateContent(content).c_str(), pItem->GetPath().c_str());
+ std::string redactPath = pItem->GetPath();
+ CURL::Decode(redactPath);
+ redactPath = CURL::GetRedacted(redactPath);
+
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Adding new item to %s:%s", TranslateContent(content).c_str(), redactPath.c_str());
long lResult = -1;
if (content == CONTENT_MOVIES)
type = "malformed";
}
if (result != CNfoFile::NO_NFO)
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Found matching %s NFO file: %s", type.c_str(), strNfoFile.c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Found matching %s NFO file: %s", type.c_str(), CURL::GetRedacted(strNfoFile).c_str());
if (result == CNfoFile::FULL_NFO)
{
if (info->Content() == CONTENT_TVSHOWS)
}
}
else
- CLog::Log(LOGDEBUG, "VideoInfoScanner: No NFO file found. Using title search for '%s'", pItem->GetPath().c_str());
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: No NFO file found. Using title search for '%s'", CURL::GetRedacted(pItem->GetPath()).c_str());
return result;
}
bool result=false;
if (m_thumb)
{
- CLog::Log(LOGDEBUG,"%s - trying to extract thumb from video file %s", __FUNCTION__, m_item.GetPath().c_str());
+ CLog::Log(LOGDEBUG,"%s - trying to extract thumb from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str());
// construct the thumb cache file
CTextureDetails details;
details.file = CTextureCache::GetCacheFile(m_target) + ".jpg";
else if (!m_item.HasVideoInfoTag() || !m_item.GetVideoInfoTag()->HasStreamDetails())
{
// No tag or no details set, so extract them
- CLog::Log(LOGDEBUG,"%s - trying to extract filestream details from video file %s", __FUNCTION__, m_item.GetPath().c_str());
+ CLog::Log(LOGDEBUG,"%s - trying to extract filestream details from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str());
result = CDVDFileInfo::GetFileStreamDetails(&m_item);
}
item.SetPath(pItem->GetVideoInfoTag()->m_strFileNameAndPath);
item.SetProperty("original_listitem_url", pItem->GetPath());
}
- CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, item.GetPath().c_str());
+ CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, CURL::GetRedacted(item.GetPath()).c_str());
if (item.GetPath().Left(17) == "pvr://recordings/")
{
EGLConfig GetEGLConfig();
+ EGLDisplay GetEGLDisplay();
+ EGLContext GetEGLContext();
protected:
virtual bool PresentRenderImpl(const CDirtyRegionList &dirty);
virtual void SetVSyncImpl(bool enable);
bool CreateWindow(RESOLUTION_INFO &res);
- EGLDisplay GetEGLDisplay();
- EGLContext GetEGLContext();
int m_displayWidth;
int m_displayHeight;
CStdString strParentPath = m_history.GetParentPath();
- CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
- CLog::Log(LOGDEBUG," ParentPath = [%s]", strParentPath.c_str());
+ CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)",
+ CURL::GetRedacted(strDirectory).c_str());
+ CLog::Log(LOGDEBUG," ParentPath = [%s]", CURL::GetRedacted(strParentPath).c_str());
// see if we can load a previously cached folder
CFileItemList cachedItems(strDirectory);
CFileItemList items;
if (!GetDirectory(directory, items))
{
- CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
+ CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", url.GetRedacted().c_str());
// Try to return to the previous directory, if not the same
// else fallback to root
if (strDirectory.Equals(strCurrentDirectory) || !Update(m_history.RemoveParentPath()))
g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
CFileItemPtr pItem=m_vecItems->Get(iItem);
- CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, pItem->GetPath().c_str());
+ CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, CURL::GetRedacted(pItem->GetPath()).c_str());
bool bResult = false;
if (pItem->IsInternetStream() || pItem->IsPlayList())