Index: project/VS2008Express/XBMC.vcproj
===================================================================
--- project/VS2008Express/XBMC.vcproj (revision 20932)
+++ project/VS2008Express/XBMC.vcproj (working copy)
@@ -3022,6 +3022,14 @@
>
+
+
+
+
Index: xbmc/Application.cpp
===================================================================
--- xbmc/Application.cpp (revision 20932)
+++ xbmc/Application.cpp (working copy)
@@ -4418,6 +4418,23 @@
if( options.fullscreen && g_renderManager.IsStarted()
&& m_gWindowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO )
SwitchToFullScreen();
+
+ // Save information about the stream if we currently have no data
+ if (item.HasVideoInfoTag())
+ {
+ CVideoInfoTag *details = m_itemCurrentFile->GetVideoInfoTag();
+ if (!details->HasStreamDetails())
+ {
+ if (m_pPlayer->GetStreamDetails(details->m_streamDetails))
+ {
+ CVideoDatabase dbs;
+ dbs.Open();
+ dbs.SetStreamDetailsForFileId(details->m_streamDetails, details->m_iFileId);
+ dbs.Close();
+ CUtil::DeleteVideoDatabaseDirectoryCache();
+ }
+ }
+ }
}
#endif
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h (working copy)
@@ -84,9 +84,14 @@
/*
* returns the nr of channels for the decoded audio stream
*/
- virtual int GetChannels() = 0;
+ virtual int GetOutputChannels() = 0;
/*
+ * returns the nr of channels in the source audio stream
+ */
+ virtual int GetSourceChannels() = 0;
+
+ /*
* returns the samplerate for the decoded audio stream
*/
virtual int GetSampleRate() = 0;
@@ -102,11 +107,18 @@
virtual bool NeedPasstrough() { return false; }
/*
- * should return codecs name
+ * should return class name
*/
virtual const char* GetName() = 0;
/*
+ *
+ * should return actual underlying codec name in the case where a codec class is
+ * representing several underlying codecs
+ */
+ virtual const char* GetCodecName() = 0;
+
+ /*
* should return amount of data decoded has buffered in preparation for next audio frame
*/
virtual int GetBufferSize() { return 0; }
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp (working copy)
@@ -212,7 +212,7 @@
m_iBuffered = 0;
}
-int CDVDAudioCodecFFmpeg::GetChannels()
+int CDVDAudioCodecFFmpeg::GetSourceChannels()
{
if (m_pCodecContext) return m_pCodecContext->channels;
return 0;
@@ -228,3 +228,13 @@
{
return 16;
}
+
+const char* CDVDAudioCodecFFmpeg::GetCodecName()
+{
+ if (m_pCodecContext && m_pCodecContext->codec)
+ {
+ return m_pCodecContext->codec->name;
+ }
+ else
+ return NULL;
+}
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h (working copy)
@@ -35,10 +35,12 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels();
+ virtual int GetOutputChannels() { return GetSourceChannels(); }
+ virtual int GetSourceChannels();
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual const char* GetName() { return "FFmpeg"; }
+ virtual const char* GetCodecName();
virtual int GetBufferSize() { return m_iBuffered; }
protected:
@@ -60,3 +62,4 @@
};
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h (working copy)
@@ -40,11 +40,13 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iOutputChannels; }
+ virtual int GetOutputChannels() { return m_iOutputChannels; }
+ virtual int GetSourceChannels() { return m_iSourceChannels; }
virtual int GetSampleRate() { return m_iSourceSampleRate; }
virtual int GetBufferSize() { return m_inputSize; }
virtual int GetBitsPerSample() { return 16; }
virtual const char* GetName() { return "liba52"; }
+ virtual const char* GetCodecName() { return "ac3"; }
protected:
void SetDefault();
@@ -77,3 +79,4 @@
int m_inputSize;
};
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h (working copy)
@@ -34,11 +34,13 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iOutputChannels; }
+ virtual int GetOutputChannels() { return m_iOutputChannels; }
+ virtual int GetSourceChannels() { return m_iSourceChannels; }
virtual int GetSampleRate() { return m_iSourceSampleRate; }
virtual int GetBufferSize() { return m_inputSize; }
virtual int GetBitsPerSample() { return 16; }
virtual const char* GetName() { return "libdts"; }
+ virtual const char* GetCodecName() { return "dts"; }
protected:
void SetDefault();
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h (working copy)
@@ -37,10 +37,12 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iSourceChannels; }
+ virtual int GetOutputChannels() { return GetSourceChannels(); }
+ virtual int GetSourceChannels() { return m_iSourceChannels; }
virtual int GetSampleRate() { return m_iSourceSampleRate; }
virtual int GetBitsPerSample() { return 16; }
virtual const char* GetName() { return "libfaad"; }
+ virtual const char* GetCodecName() { return "aac"; }
virtual int GetBufferSize() { return m_InputBufferSize; }
private:
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.cpp (working copy)
@@ -153,6 +153,7 @@
m_iSourceSampleRate = m_frame.header.samplerate;
m_iSourceChannels = (m_frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2;
m_iSourceBitrate = m_frame.header.bitrate;
+ m_iSourceLayer = m_frame.header.layer;
/*
switch (this->frame.header.layer) {
@@ -244,3 +245,18 @@
m_iInputBufferSize = 0;
}
}
+
+const char* CDVDAudioCodecLibMad::GetCodecName()
+{
+ switch (m_iSourceLayer)
+ {
+ case MAD_LAYER_I:
+ return "mp1";
+ case MAD_LAYER_II:
+ return "mp2";
+ case MAD_LAYER_III:
+ return "mp3";
+ default:
+ return "mpa";
+ }
+}
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h (working copy)
@@ -37,10 +37,12 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iSourceChannels; }
+ virtual int GetOutputChannels() { return GetSourceChannels(); }
+ virtual int GetSourceChannels() { return m_iSourceChannels; }
virtual int GetSampleRate() { return m_iSourceSampleRate; }
virtual int GetBitsPerSample() { return 16; }
virtual const char* GetName() { return "libmad"; }
+ virtual const char* GetCodecName();
virtual int GetBufferSize() { return m_iInputBufferSize; }
private:
@@ -48,6 +50,7 @@
int m_iSourceSampleRate;
int m_iSourceChannels;
int m_iSourceBitrate;
+ int m_iSourceLayer;
bool m_bInitialized;
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLPcm.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLPcm.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLPcm.h (working copy)
@@ -35,6 +35,7 @@
virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
virtual int Decode(BYTE* pData, int iSize);
virtual const char* GetName() { return "lpcm"; }
+ virtual const char* GetCodecName() { return "lpcm"; }
protected:
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp (working copy)
@@ -369,7 +369,7 @@
m_Synced = false;
}
-int CDVDAudioCodecPassthrough::GetChannels()
+int CDVDAudioCodecPassthrough::GetOutputChannels()
{
//Can't return correct channels here as this is used to keep sync.
//should probably have some other way to find out this
@@ -386,3 +386,12 @@
return OUT_SAMPLESIZE;
}
+const char* CDVDAudioCodecPassthrough::GetCodecName()
+{
+ if (m_Codec == CODEC_ID_AC3)
+ return "ac3";
+ if (m_Codec == CODEC_ID_DTS)
+ return "dts";
+ return NULL;
+}
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h (working copy)
@@ -36,11 +36,13 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels();
+ virtual int GetOutputChannels();
+ virtual int GetSourceChannels() { return 0; }
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual bool NeedPasstrough() { return true; }
virtual const char* GetName() { return "passthrough"; }
+ virtual const char* GetCodecName();
private:
int ParseFrame(BYTE* data, int size, BYTE** frame, int* framesize);
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp (working copy)
@@ -289,7 +289,7 @@
//SetDefault();
}
-int CDVDAudioCodecPcm::GetChannels()
+int CDVDAudioCodecPcm::GetOutputChannels()
{
return m_iOutputChannels;
}
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h (working copy)
@@ -33,10 +33,12 @@
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels();
+ virtual int GetOutputChannels();
+ virtual int GetSourceChannels() { return m_iSourceChannels; }
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual const char* GetName() { return "pcm"; }
+ virtual const char* GetCodecName() { return "pcm"; }
protected:
virtual void SetDefault();
Index: xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h (working copy)
@@ -136,7 +136,19 @@
/*
*
- * should return codecs name
+ * should return class name
*/
virtual const char* GetName() = 0;
+
+ /*
+ * should return actual underlying codec name in the case where a codec class is
+ * representing several underlying codecs
+ */
+ virtual const char* GetCodecName() = 0;
+
+ /*
+ * should return actual underlying codec name in the case where a codec class is
+ * representing several underlying codecs
+ */
+ virtual int GetPictureWidth() = 0;
};
Index: xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp (working copy)
@@ -510,6 +510,23 @@
}
}
+const char* CDVDVideoCodecFFmpeg::GetCodecName()
+{
+ if (m_pCodecContext && m_pCodecContext->codec)
+ {
+ return m_pCodecContext->codec->name;
+ }
+ else
+ return NULL;
+}
+
+int CDVDVideoCodecFFmpeg::GetPictureWidth()
+{
+ if (m_pCodecContext)
+ return m_pCodecContext->width;
+ return m_iPictureWidth;
+}
+
#ifdef HAVE_LIBVDPAU
CVDPAU* CDVDVideoCodecFFmpeg::GetContextVDPAU()
{
Index: xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h (working copy)
@@ -40,6 +40,8 @@
virtual bool GetPicture(DVDVideoPicture* pDvdVideoPicture);
virtual void SetDropState(bool bDrop);
virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
+ virtual const char* GetCodecName();
+ virtual int GetPictureWidth();
#ifdef HAVE_LIBVDPAU
CVDPAU* GetContextVDPAU();
@@ -67,3 +69,4 @@
bool m_UsingSoftware;
};
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.cpp (working copy)
@@ -582,3 +582,10 @@
// simplify (pixel_width, pixel_height);
return (height == 576) ? 1 : 2;
}
+
+int CDVDVideoCodecLibMpeg2::GetPictureWidth()
+{
+ if (m_pCurrentBuffer)
+ return m_pCurrentBuffer->iWidth;
+ return 0;
+}
Index: xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecLibMpeg2.h (working copy)
@@ -38,6 +38,8 @@
virtual void SetDropState(bool bDrop);
virtual const char* GetName() { return "libmpeg2"; }
+ virtual const char* GetCodecName() { return "mpeg2"; }
+ virtual int GetPictureWidth();
protected:
DVDVideoPicture* GetBuffer(unsigned int width, unsigned int height);
Index: xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
===================================================================
--- xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h (working copy)
@@ -294,4 +294,8 @@
*/
CDemuxStreamSubtitle* GetStreamFromSubtitleId(int iSubtitleIndex);
+ /*
+ * convert a demux-specific codecid to something presentable to the user
+ */
+ virtual void CodecIDToName(CodecID idCodec, CStdString &strName) {};
};
Index: xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp (working copy)
@@ -1113,3 +1113,13 @@
return false;
#endif
}
+
+void CDVDDemuxFFmpeg::CodecIDToName(CodecID idCodec, CStdString &strName)
+{
+ if (m_dllAvCodec.IsLoaded())
+ {
+ AVCodec *codec = m_dllAvCodec.avcodec_find_decoder(idCodec);
+ if (codec)
+ strName = codec->name;
+ }
+}
Index: xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
===================================================================
--- xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h (working copy)
@@ -96,8 +96,8 @@
int GetChapterCount();
int GetChapter();
void GetChapterName(std::string& strChapterName);
+ void CodecIDToName(CodecID idCodec, CStdString& strName);
-
bool Aborted();
AVFormatContext* m_pFormatContext;
Index: xbmc/cores/dvdplayer/DVDFileInfo.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDFileInfo.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDFileInfo.cpp (working copy)
@@ -23,8 +23,10 @@
#include "FileItem.h"
#include "Settings.h"
#include "Picture.h"
+#include "VideoInfoTag.h"
+#include "Util.h"
+#include "FileSystem/StackDirectory.h"
-
#include "DVDFileInfo.h"
#include "DVDStreamInfo.h"
#include "DVDInputStreams/DVDInputStream.h"
@@ -66,7 +68,7 @@
return false;
}
-bool CDVDFileInfo::ExtractThumb(const CStdString &strPath, const CStdString &strTarget)
+bool CDVDFileInfo::ExtractThumb(const CStdString &strPath, const CStdString &strTarget, CStreamDetails *pStreamDetails)
{
int nTime = timeGetTime();
CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strPath, "");
@@ -112,6 +114,9 @@
return false;
}
+ if (pStreamDetails)
+ DemuxerToStreamDetails(pDemuxer, *pStreamDetails);
+
CDemuxStream* pStream = NULL;
int nVideoStream = -1;
for (int i = 0; i < pDemuxer->GetNrOfStreams(); i++)
@@ -310,3 +315,95 @@
}
+/**
+ * \brief Open the item pointed to by pItem and extact streamdetails
+ * \return true if the stream details have changed
+ */
+bool CDVDFileInfo::GetFileStreamDetails(CFileItem *pItem)
+{
+ if (!pItem)
+ return false;
+
+ CStdString strFileNameAndPath;
+ if (pItem->HasVideoInfoTag())
+ {
+ strFileNameAndPath = pItem->GetVideoInfoTag()->m_strFileNameAndPath;
+ if (CUtil::IsStack(strFileNameAndPath))
+ strFileNameAndPath = DIRECTORY::CStackDirectory::GetFirstStackedFile(strFileNameAndPath);
+ }
+ else
+ return false;
+
+ CDVDInputStream *pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFileNameAndPath, "");
+ if (!pInputStream)
+ return false;
+
+ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD) || !pInputStream->Open(strFileNameAndPath.c_str(), ""))
+ {
+ delete pInputStream;
+ return false;
+ }
+
+ CDVDDemux *pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(pInputStream);
+ if (pDemuxer)
+ {
+ bool retVal = DemuxerToStreamDetails(pDemuxer, pItem->GetVideoInfoTag()->m_streamDetails);
+ delete pDemuxer;
+ delete pInputStream;
+ return retVal;
+ }
+ else
+ {
+ delete pInputStream;
+ return false;
+ }
+}
+
+/* returns true if details have been added */
+bool CDVDFileInfo::DemuxerToStreamDetails(CDVDDemux *pDemux, CStreamDetails &details)
+{
+ bool retVal = false;
+ details.Reset();
+
+ for (int iStream=0; iStreamGetNrOfStreams(); iStream++)
+ {
+ CDemuxStream *stream = pDemux->GetStream(iStream);
+ if (stream->type == STREAM_VIDEO)
+ {
+ CStreamDetailVideo *p = new CStreamDetailVideo();
+ p->m_iWidth = ((CDemuxStreamVideo *)stream)->iWidth;
+ p->m_iHeight = ((CDemuxStreamVideo *)stream)->iHeight;
+ float aspect = ((CDemuxStreamVideo *)stream)->fAspect;
+ if (aspect != 0.0f)
+ p->m_strAspect.Format("%.2f", aspect); // how many digits should we store?
+ pDemux->CodecIDToName(stream->codec, p->m_strCodec);
+ details.AddStream(p);
+ retVal = true;
+ }
+
+ else if (stream->type == STREAM_AUDIO)
+ {
+ CStreamDetailAudio *p = new CStreamDetailAudio();
+ p->m_iChannels = ((CDemuxStreamAudio *)stream)->iChannels;
+ if (stream->language)
+ p->m_strLanguage = stream->language;
+ pDemux->CodecIDToName(stream->codec, p->m_strCodec);
+ details.AddStream(p);
+ retVal = true;
+ }
+
+ else if (stream->type == STREAM_SUBTITLE)
+ {
+ if (stream->language)
+ {
+ CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
+ p->m_strLanguage = stream->language;
+ details.AddStream(p);
+ retVal = true;
+ }
+ }
+ } /* for iStream */
+
+ details.DetermineBestStreams();
+ return retVal;
+}
Index: xbmc/cores/dvdplayer/DVDFileInfo.h
===================================================================
--- xbmc/cores/dvdplayer/DVDFileInfo.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDFileInfo.h (working copy)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 Team XBMC
+ * Copyright (C) 2005-2009 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -21,15 +21,22 @@
#pragma once
#include "StdString.h"
+#include "utils/StreamDetails.h"
class CFileItem;
+class CDVDDemux;
class CDVDFileInfo
{
public:
- static bool ExtractThumb(const CStdString &strPath, const CStdString &strTarget);
+ // Extract a thumbnail immage from the media at strPath an image file in strTarget, optionally populating a streamdetails class with the data
+ static bool ExtractThumb(const CStdString &strPath, const CStdString &strTarget, CStreamDetails *pStreamDetails);
// GetFileMetaData will fill pItem's properties according to what can be extracted from the file.
static void GetFileMetaData(const CStdString &strPath, CFileItem *pItem);
+
+ // Probe the files streams and store the info in the VideoInfoTag
+ static bool GetFileStreamDetails(CFileItem *pItem);
+ static bool DemuxerToStreamDetails(CDVDDemux *pDemux, CStreamDetails &details);
static bool GetFileDuration(const CStdString &path, int &duration);
};
Index: xbmc/cores/dvdplayer/DVDPlayer.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayer.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayer.cpp (working copy)
@@ -36,6 +36,8 @@
#include "DVDCodecs/DVDCodecs.h"
#include "DVDCodecs/DVDFactoryCodec.h"
+#include "DVDFileInfo.h"
+
#include "Util.h"
#include "utils/GUIInfoManager.h"
#include "Application.h"
@@ -3025,6 +3027,38 @@
return false;
}
+int CDVDPlayer::GetChannels()
+{
+ int retVal = m_dvdPlayerAudio.GetChannels();
+ // If the audio player returns 0 channels, ask the demuxer
+ if (!retVal && m_pDemuxer && (m_CurrentAudio.id != -1))
+ {
+ CDemuxStreamAudio* stream = static_cast(m_pDemuxer->GetStream(m_CurrentAudio.id));
+ if (stream && (stream->iChannels > retVal))
+ retVal = stream->iChannels;
+ }
+
+ return retVal;
+}
+
+CStdString CDVDPlayer::GetAudioCodecName()
+{
+ return m_dvdPlayerAudio.GetCodecName();
+}
+
+CStdString CDVDPlayer::GetVideoCodecName()
+{
+ return m_dvdPlayerVideo.GetCodecName();
+}
+
+bool CDVDPlayer::GetStreamDetails(CStreamDetails &details)
+{
+ if (m_pDemuxer)
+ return CDVDFileInfo::DemuxerToStreamDetails(m_pDemuxer, details);
+ else
+ return false;
+}
+
CDVDPlayer::CPlayerSeek::CPlayerSeek(CDVDPlayer* player)
: m_player(*player)
{
Index: xbmc/cores/dvdplayer/DVDPlayer.h
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayer.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayer.h (working copy)
@@ -192,6 +192,11 @@
virtual int GetAudioBitrate();
virtual int GetVideoBitrate();
virtual int GetSourceBitrate();
+ virtual int GetChannels();
+ virtual CStdString GetAudioCodecName();
+ virtual CStdString GetVideoCodecName();
+ virtual int GetPictureWidth() { return m_dvdPlayerVideo.GetPictureWidth(); }
+ virtual bool GetStreamDetails(CStreamDetails &details);
virtual bool GetCurrentSubtitle(CStdString& strSubtitle);
@@ -363,3 +368,4 @@
CPlayerOptions m_PlayerOptions;
};
+
Index: xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerAudio.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayerAudio.cpp (working copy)
@@ -259,7 +259,7 @@
}
/* update codec information from what codec gave ut */
- m_streaminfo.channels = m_pAudioCodec->GetChannels();
+ m_streaminfo.channels = m_pAudioCodec->GetSourceChannels();
m_streaminfo.samplerate = m_pAudioCodec->GetSampleRate();
LeaveCriticalSection(&m_critCodecSection);
@@ -316,7 +316,7 @@
// get decoded data and the size of it
audioframe.size = m_pAudioCodec->GetData(&audioframe.data);
audioframe.pts = m_audioClock;
- audioframe.channels = m_pAudioCodec->GetChannels();
+ audioframe.channels = m_pAudioCodec->GetOutputChannels();
audioframe.bits_per_sample = m_pAudioCodec->GetBitsPerSample();
audioframe.sample_rate = m_pAudioCodec->GetSampleRate();
audioframe.passthrough = m_pAudioCodec->NeedPasstrough();
@@ -766,3 +766,19 @@
{
return (int)m_audioStats.GetBitrate();
}
+
+std::string CDVDPlayerAudio::GetCodecName()
+{
+ if (m_pAudioCodec)
+ return m_pAudioCodec->GetCodecName();
+ else
+ return "";
+}
+
+int CDVDPlayerAudio::GetChannels()
+{
+ if (m_pAudioCodec)
+ return m_pAudioCodec->GetSourceChannels();
+ else
+ return m_streaminfo.channels;
+}
Index: xbmc/cores/dvdplayer/DVDPlayerAudio.h
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerAudio.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayerAudio.h (working copy)
@@ -107,7 +107,9 @@
void SetDynamicRangeCompression(long drc) { m_dvdAudio.SetDynamicRangeCompression(drc); }
std::string GetPlayerInfo();
+ std::string GetCodecName();
int GetAudioBitrate();
+ int GetChannels();
// holds stream information for current playing stream
CDVDStreamInfo m_streaminfo;
Index: xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerVideo.cpp (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp (working copy)
@@ -998,3 +998,16 @@
return (int)m_videoStats.GetBitrate();
}
+std::string CDVDPlayerVideo::GetCodecName()
+{
+ if (m_pVideoCodec)
+ return m_pVideoCodec->GetCodecName();
+ return "";
+}
+
+int CDVDPlayerVideo::GetPictureWidth()
+{
+ if (m_pVideoCodec)
+ return m_pVideoCodec->GetPictureWidth();
+ return 0;
+}
Index: xbmc/cores/dvdplayer/DVDPlayerVideo.h
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerVideo.h (revision 20932)
+++ xbmc/cores/dvdplayer/DVDPlayerVideo.h (working copy)
@@ -97,6 +97,8 @@
double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */
std::string GetPlayerInfo();
int GetVideoBitrate();
+ std::string GetCodecName();
+ int GetPictureWidth();
void SetSpeed(int iSpeed);
@@ -176,3 +178,4 @@
CRITICAL_SECTION m_critCodecSection;
};
+
Index: xbmc/cores/IPlayer.h
===================================================================
--- xbmc/cores/IPlayer.h (revision 20932)
+++ xbmc/cores/IPlayer.h (working copy)
@@ -23,6 +23,7 @@
#include "IAudioCallback.h"
#include "Key.h"
+#include "utils/StreamDetails.h"
class IPlayerCallback
{
@@ -122,7 +123,10 @@
virtual int GetChannels(){ return 0;};
virtual int GetBitsPerSample(){ return 0;};
virtual int GetSampleRate(){ return 0;};
- virtual CStdString GetCodecName(){ return "";};
+ virtual CStdString GetAudioCodecName(){ return "";}
+ virtual CStdString GetVideoCodecName(){ return "";}
+ virtual int GetPictureWidth(){ return 0;}
+ virtual bool GetStreamDetails(CStreamDetails &details){ return false;}
virtual void ToFFRW(int iSpeed = 0){};
// Skip to next track/item inside the current media (if supported).
virtual bool SkipNext(){return false;}
Index: xbmc/cores/paplayer/DVDPlayerCodec.cpp
===================================================================
--- xbmc/cores/paplayer/DVDPlayerCodec.cpp (revision 20932)
+++ xbmc/cores/paplayer/DVDPlayerCodec.cpp (working copy)
@@ -151,7 +151,7 @@
// We always ask ffmpeg to return s16le
m_BitsPerSample = m_pAudioCodec->GetBitsPerSample();
m_SampleRate = m_pAudioCodec->GetSampleRate();
- m_Channels = m_pAudioCodec->GetChannels();
+ m_Channels = m_pAudioCodec->GetSourceChannels();
}
Index: xbmc/cores/paplayer/PAPlayer.cpp
===================================================================
--- xbmc/cores/paplayer/PAPlayer.cpp (revision 20932)
+++ xbmc/cores/paplayer/PAPlayer.cpp (working copy)
@@ -803,7 +803,7 @@
return 0;
}
-CStdString PAPlayer::GetCodecName()
+CStdString PAPlayer::GetAudioCodecName()
{
ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
if (codec)
Index: xbmc/cores/paplayer/PAPlayer.h
===================================================================
--- xbmc/cores/paplayer/PAPlayer.h (revision 20932)
+++ xbmc/cores/paplayer/PAPlayer.h (working copy)
@@ -86,7 +86,7 @@
virtual int GetChannels();
virtual int GetBitsPerSample();
virtual int GetSampleRate();
- virtual CStdString GetCodecName();
+ virtual CStdString GetAudioCodecName();
virtual __int64 GetTime();
virtual void ResetTime();
virtual void SeekTime(__int64 iTime = 0);
@@ -207,3 +207,4 @@
};
+
Index: xbmc/GUIWindowVideoBase.cpp
===================================================================
--- xbmc/GUIWindowVideoBase.cpp (revision 20932)
+++ xbmc/GUIWindowVideoBase.cpp (working copy)
@@ -78,6 +78,7 @@
: CGUIMediaWindow(dwID, xmlFile)
{
m_thumbLoader.SetObserver(this);
+ m_thumbLoader.SetStreamDetailsObserver(this);
}
CGUIWindowVideoBase::~CGUIWindowVideoBase()
@@ -955,6 +956,20 @@
CGUIMediaWindow::OnClick(iItem);
}
+void CGUIWindowVideoBase::OnStreamDetails(const CStreamDetails &details, const CStdString &strFileName, long lFileId)
+{
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ if (lFileId < 0)
+ db.SetStreamDetailsForFile(details, strFileName);
+ else
+ db.SetStreamDetailsForFileId(details, lFileId);
+
+ db.Close();
+ }
+}
+
void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &buttons)
{
CFileItemPtr item;
Index: xbmc/GUIWindowVideoBase.h
===================================================================
--- xbmc/GUIWindowVideoBase.h (revision 20932)
+++ xbmc/GUIWindowVideoBase.h (working copy)
@@ -26,7 +26,7 @@
#include "PlayListPlayer.h"
#include "ThumbLoader.h"
-class CGUIWindowVideoBase : public CGUIMediaWindow, public IBackgroundLoaderObserver
+class CGUIWindowVideoBase : public CGUIMediaWindow, public IBackgroundLoaderObserver, public IStreamDetailsObserver
{
public:
CGUIWindowVideoBase(DWORD dwID, const CStdString &xmlFile);
@@ -40,6 +40,7 @@
void AddToDatabase(int iItem);
static void OnScan(const CStdString& strPath, const SScraperInfo& info, const VIDEO::SScanSettings& settings);
virtual void OnInfo(CFileItem* pItem, const SScraperInfo& info);
+ virtual void OnStreamDetails(const CStreamDetails &details, const CStdString &strFileName, long lFileId);
static void MarkUnWatched(const CFileItemPtr &pItem);
static void MarkWatched(const CFileItemPtr &pItem);
static void UpdateVideoTitle(const CFileItem* pItem);
Index: xbmc/GUIWindowVideoNav.cpp
===================================================================
--- xbmc/GUIWindowVideoNav.cpp (revision 20932)
+++ xbmc/GUIWindowVideoNav.cpp (working copy)
@@ -393,6 +393,18 @@
}
}
+void CGUIWindowVideoNav::OnItemLoaded(CFileItem* pItem)
+{
+ /* Notification from DVDFileInfo's scanner that either a thumb has been generated or stream
+ info is now present. Setting the thumbnail automatically invalidates, but we need to
+ invalidate for new stream details */
+ if (pItem->IsVideoDb() && pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->HasStreamDetails())
+ {
+ CUtil::DeleteVideoDatabaseDirectoryCache();
+ pItem->SetInvalid();
+ }
+}
+
bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
{
if (m_bDisplayEmptyDatabaseMessage)
Index: xbmc/GUIWindowVideoNav.h
===================================================================
--- xbmc/GUIWindowVideoNav.h (revision 20932)
+++ xbmc/GUIWindowVideoNav.h (working copy)
@@ -43,7 +43,7 @@
static bool DeleteItem(CFileItem* pItem, bool bUnavailable=false);
protected:
- virtual void OnItemLoaded(CFileItem* pItem) {};
+ virtual void OnItemLoaded(CFileItem* pItem);
void OnLinkMovieToTvShow(int itemnumber, bool bRemove);
// override base class methods
virtual bool GetDirectory(const CStdString &strDirectory, CFileItemList &items);
Index: xbmc/ThumbLoader.cpp
===================================================================
--- xbmc/ThumbLoader.cpp (revision 20932)
+++ xbmc/ThumbLoader.cpp (working copy)
@@ -36,7 +36,8 @@
using namespace XFILE;
using namespace DIRECTORY;
-CThumbLoader::CThumbLoader()
+CThumbLoader::CThumbLoader(int nThreads) :
+ CBackgroundInfoLoader(nThreads)
{
}
@@ -65,7 +66,11 @@
return pItem->HasThumbnail();
}
-CVideoThumbLoader::CVideoThumbLoader()
+CVideoThumbLoader::CVideoThumbLoader() :
+ CThumbLoader(1), m_pStreamDetailsObs(NULL)
+ // ^^^ It is REQUIRED that only one background thread be created until the demuxers
+ // are threadsafe. The CDVDDemuxFFmpeg::ff_avutil_log's buffer is not safe, and
+ // avcodec_open/close may not be compiled threadsafe.
{
}
@@ -82,7 +87,7 @@
{
}
-bool CVideoThumbLoader::ExtractThumb(const CStdString &strPath, const CStdString &strTarget)
+bool CVideoThumbLoader::ExtractThumb(const CStdString &strPath, const CStdString &strTarget, CStreamDetails *pStreamDetails)
{
if (!g_guiSettings.GetBool("myvideos.autothumb"))
return false;
@@ -96,12 +101,14 @@
return false;
CLog::Log(LOGDEBUG,"%s - trying to extract thumb from video file %s", __FUNCTION__, strPath.c_str());
- return CDVDFileInfo::ExtractThumb(strPath, strTarget);
+ return CDVDFileInfo::ExtractThumb(strPath, strTarget, pStreamDetails);
}
bool CVideoThumbLoader::LoadItem(CFileItem* pItem)
{
- if (pItem->m_bIsShareOrDrive) return true;
+ if (pItem->m_bIsShareOrDrive) return false;
+
+ bool retVal = false;
if (pItem->IsVideoDb() && pItem->HasVideoInfoTag() && !pItem->HasThumbnail())
{
if (pItem->m_bIsFolder && pItem->GetVideoInfoTag()->m_iSeason > -1)
@@ -114,6 +121,7 @@
pItem->SetProperty("AutoThumbImage",item.GetProperty("AutoThumbImage"));
pItem->SetProperty("fanart_image",item.GetProperty("fanart_image"));
pItem->SetThumbnailImage(item.GetThumbnailImage());
+ pItem->GetVideoInfoTag()->m_streamDetails = item.GetVideoInfoTag()->m_streamDetails;
}
return bResult;
}
@@ -131,15 +139,19 @@
cachedThumb = strPath + "auto-" + strFileName;
if (pItem->IsVideo() && !pItem->IsInternetStream() && !pItem->IsPlayList() && !CFile::Exists(cachedThumb))
{
+ CStreamDetails details;
if (pItem->IsStack())
{
CStackDirectory stack;
- CVideoThumbLoader::ExtractThumb(stack.GetFirstStackedFile(pItem->m_strPath), cachedThumb);
+ CVideoThumbLoader::ExtractThumb(stack.GetFirstStackedFile(pItem->m_strPath), cachedThumb, &details);
}
else
{
- CVideoThumbLoader::ExtractThumb(pItem->m_strPath, cachedThumb);
+ CVideoThumbLoader::ExtractThumb(pItem->m_strPath, cachedThumb, &details);
}
+
+ if (details.HasItems() && m_pStreamDetailsObs)
+ m_pStreamDetailsObs->OnStreamDetails(details, pItem->m_strPath, -1);
}
if (CFile::Exists(cachedThumb))
@@ -160,10 +172,21 @@
pItem->SetProperty("fanart_image",pItem->GetCachedFanart());
}
+ if (!pItem->m_bIsFolder && !pItem->IsInternetStream() &&
+ pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->HasStreamDetails())
+ {
+ if (CDVDFileInfo::GetFileStreamDetails(pItem) && m_pStreamDetailsObs)
+ {
+ CVideoInfoTag *info = pItem->GetVideoInfoTag();
+ m_pStreamDetailsObs->OnStreamDetails(info->m_streamDetails, "", info->m_iFileId);
+ retVal = true;
+ }
+ }
+
// if (pItem->IsVideo() && !pItem->IsInternetStream())
// CDVDPlayer::GetFileMetaData(pItem->m_strPath, pItem);
- return true;
+ return retVal;
}
CProgramThumbLoader::CProgramThumbLoader()
Index: xbmc/ThumbLoader.h
===================================================================
--- xbmc/ThumbLoader.h (revision 20932)
+++ xbmc/ThumbLoader.h (working copy)
@@ -22,11 +22,12 @@
#ifndef THUMBLOADER_H
#define THUMBLOADER_H
#include "BackgroundInfoLoader.h"
+#include "utils/StreamDetails.h"
class CThumbLoader : public CBackgroundInfoLoader
{
public:
- CThumbLoader();
+ CThumbLoader(int nThreads=-1);
virtual ~CThumbLoader();
bool LoadRemoteThumb(CFileItem *pItem);
@@ -38,11 +39,14 @@
CVideoThumbLoader();
virtual ~CVideoThumbLoader();
virtual bool LoadItem(CFileItem* pItem);
- bool ExtractThumb(const CStdString &strPath, const CStdString &strTarget);
+ bool ExtractThumb(const CStdString &strPath, const CStdString &strTarget, CStreamDetails *pStreamDetails);
+ void SetStreamDetailsObserver(IStreamDetailsObserver *pObs) { m_pStreamDetailsObs = pObs; }
protected:
virtual void OnLoaderStart() ;
virtual void OnLoaderFinish() ;
+
+ IStreamDetailsObserver *m_pStreamDetailsObs;
};
class CProgramThumbLoader : public CThumbLoader
Index: xbmc/utils/GUIInfoManager.cpp
===================================================================
--- xbmc/utils/GUIInfoManager.cpp (revision 20932)
+++ xbmc/utils/GUIInfoManager.cpp (working copy)
@@ -518,6 +518,11 @@
else if (strTest.Equals("videoplayer.tagline")) return VIDEOPLAYER_TAGLINE;
else if (strTest.Equals("videoplayer.hasinfo")) return VIDEOPLAYER_HAS_INFO;
else if (strTest.Equals("videoplayer.trailer")) return VIDEOPLAYER_TRAILER;
+ else if (strTest.Equals("videoplayer.videocodec")) return VIDEOPLAYER_VIDEO_CODEC;
+ else if (strTest.Equals("videoplayer.videoresolution")) return VIDEOPLAYER_VIDEO_RESOLUTION;
+ else if (strTest.Equals("videoplayer.audiocodec")) return VIDEOPLAYER_AUDIO_CODEC;
+ else if (strTest.Equals("videoplayer.audiochannels")) return VIDEOPLAYER_AUDIO_CHANNELS;
+
}
else if (strCategory.Equals("playlist"))
{
@@ -869,6 +874,13 @@
else if (info.Equals("trailer")) return LISTITEM_TRAILER;
else if (info.Equals("starrating")) return LISTITEM_STAR_RATING;
else if (info.Equals("sortletter")) return LISTITEM_SORT_LETTER;
+ else if (info.Equals("videocodec")) return LISTITEM_VIDEO_CODEC;
+ else if (info.Equals("videoresolution")) return LISTITEM_VIDEO_RESOLUTION;
+ else if (info.Equals("videoaspect")) return LISTITEM_VIDEO_ASPECT;
+ else if (info.Equals("audiocodec")) return LISTITEM_AUDIO_CODEC;
+ else if (info.Equals("audiochannels")) return LISTITEM_AUDIO_CHANNELS;
+ else if (info.Equals("audiolanguage")) return LISTITEM_AUDIO_LANGUAGE;
+ else if (info.Equals("subtitlelanguage")) return LISTITEM_SUBTITLE_LANGUAGE;
else if (info.Left(9).Equals("property(")) return AddListItemProp(info.Mid(9, info.GetLength() - 10));
return 0;
}
@@ -1033,6 +1045,22 @@
case VIDEOPLAYER_TRAILER:
strLabel = GetVideoLabel(info);
break;
+ case VIDEOPLAYER_VIDEO_CODEC:
+ if(g_application.IsPlaying() && g_application.m_pPlayer)
+ strLabel = g_application.m_pPlayer->GetVideoCodecName();
+ break;
+ case VIDEOPLAYER_VIDEO_RESOLUTION:
+ if(g_application.IsPlaying() && g_application.m_pPlayer)
+ return VideoWidthToResolutionDescription(g_application.m_pPlayer->GetPictureWidth());
+ break;
+ case VIDEOPLAYER_AUDIO_CODEC:
+ if(g_application.IsPlaying() && g_application.m_pPlayer)
+ strLabel = g_application.m_pPlayer->GetAudioCodecName();
+ break;
+ case VIDEOPLAYER_AUDIO_CHANNELS:
+ if(g_application.IsPlaying() && g_application.m_pPlayer)
+ strLabel.Format("%i", g_application.m_pPlayer->GetChannels());
+ break;
case PLAYLIST_LENGTH:
case PLAYLIST_POSITION:
case PLAYLIST_RANDOM:
@@ -2797,7 +2825,7 @@
case MUSICPLAYER_CODEC:
{
CStdString strCodec;
- strCodec.Format("%s", g_application.m_pPlayer->GetCodecName().c_str());
+ strCodec.Format("%s", g_application.m_pPlayer->GetAudioCodecName().c_str());
return strCodec;
}
break;
@@ -3477,7 +3505,7 @@
return item;
}
-CStdString CGUIInfoManager::GetItemLabel(const CFileItem *item, int info ) const
+CStdString CGUIInfoManager::GetItemLabel(const CFileItem *item, int info) const
{
if (!item) return "";
@@ -3764,34 +3792,76 @@
return letter;
}
break;
+ case LISTITEM_VIDEO_CODEC:
+ if (item->HasVideoInfoTag())
+ return item->GetVideoInfoTag()->m_streamDetails.GetVideoCodec();
+ break;
+ case LISTITEM_VIDEO_RESOLUTION:
+ if (item->HasVideoInfoTag())
+ return VideoWidthToResolutionDescription(item->GetVideoInfoTag()->m_streamDetails.GetVideoWidth());
+ break;
+ case LISTITEM_VIDEO_ASPECT:
+ if (item->HasVideoInfoTag())
+ return item->GetVideoInfoTag()->m_streamDetails.GetVideoAspect();
+ break;
+ case LISTITEM_AUDIO_CODEC:
+ if (item->HasVideoInfoTag())
+ {
+ return item->GetVideoInfoTag()->m_streamDetails.GetAudioCodec();
+ }
+ break;
+ case LISTITEM_AUDIO_CHANNELS:
+ if (item->HasVideoInfoTag())
+ {
+ CStdString strResult;
+ int iChannels = item->GetVideoInfoTag()->m_streamDetails.GetAudioChannels();
+ if (iChannels > -1)
+ strResult.Format("%i", iChannels);
+ return strResult;
+ }
+ break;
+ case LISTITEM_AUDIO_LANGUAGE:
+ if (item->HasVideoInfoTag())
+ return item->GetVideoInfoTag()->m_streamDetails.GetAudioLanguage();
+ break;
+ case LISTITEM_SUBTITLE_LANGUAGE:
+ if (item->HasVideoInfoTag())
+ return item->GetVideoInfoTag()->m_streamDetails.GetSubtitleLanguage();
+ break;
}
return "";
}
CStdString CGUIInfoManager::GetItemImage(const CFileItem *item, int info) const
{
- if (info == LISTITEM_RATING)
- { // old song rating format
- CStdString rating;
- if (item->HasMusicInfoTag())
+ switch (info)
+ {
+ case LISTITEM_RATING: // old song rating format
{
- rating.Format("songrating%c.png", item->GetMusicInfoTag()->GetRating());
+ CStdString rating;
+ if (item->HasMusicInfoTag())
+ {
+ rating.Format("songrating%c.png", item->GetMusicInfoTag()->GetRating());
+ return rating;
+ }
+ }
+ break;
+ case LISTITEM_STAR_RATING:
+ {
+ CStdString rating;
+ if (item->HasVideoInfoTag())
+ { // rating for videos is assumed 0..10, so convert to 0..5
+ rating.Format("rating%d.png", (long)((item->GetVideoInfoTag()->m_fRating * 0.5f) + 0.5f));
+ }
+ else if (item->HasMusicInfoTag())
+ { // song rating.
+ rating.Format("rating%c.png", item->GetMusicInfoTag()->GetRating());
+ }
return rating;
}
- }
- else if (info == LISTITEM_STAR_RATING)
- {
- CStdString rating;
- if (item->HasVideoInfoTag())
- { // rating for videos is assumed 0..10, so convert to 0..5
- rating.Format("rating%d.png", (long)((item->GetVideoInfoTag()->m_fRating * 0.5f) + 0.5f));
- }
- else if (item->HasMusicInfoTag())
- { // song rating.
- rating.Format("rating%c.png", item->GetMusicInfoTag()->GetRating());
- }
- return rating;
- }
+ break;
+ } /* switch (info) */
+
return GetItemLabel(item, info);
}
@@ -4002,6 +4072,20 @@
m_currentFile->m_lStartOffset = 0;
}
+CStdString CGUIInfoManager::VideoWidthToResolutionDescription(int iWidth) const
+{
+ if (iWidth == 0)
+ return "";
+
+ // Give HD resoultions 80 pixels of fudge so like 1264 width is still considered 720
+ if (iWidth < 1200)
+ return "480";
+ else if (iWidth < 1840)
+ return "720";
+ else
+ return "1080";
+}
+
const CFileItem& CGUIInfoManager::GetCurrentSlide() const
{
return *m_currentSlide;
Index: xbmc/utils/GUIInfoManager.h
===================================================================
--- xbmc/utils/GUIInfoManager.h (revision 20932)
+++ xbmc/utils/GUIInfoManager.h (working copy)
@@ -241,6 +241,10 @@
#define VIDEOPLAYER_TOP250 283
#define VIDEOPLAYER_RATING_AND_VOTES 284
#define VIDEOPLAYER_TRAILER 285
+#define VIDEOPLAYER_VIDEO_CODEC 286
+#define VIDEOPLAYER_VIDEO_RESOLUTION 287
+#define VIDEOPLAYER_AUDIO_CODEC 288
+#define VIDEOPLAYER_AUDIO_CHANNELS 289
#define AUDIOSCROBBLER_ENABLED 300
#define AUDIOSCROBBLER_CONN_STATE 301
@@ -464,6 +468,13 @@
#define LISTITEM_SORT_LETTER (LISTITEM_START + 43)
#define LISTITEM_ALBUM_ARTIST (LISTITEM_START + 44)
#define LISTITEM_FOLDERNAME (LISTITEM_START + 45)
+#define LISTITEM_VIDEO_CODEC (LISTITEM_START + 46)
+#define LISTITEM_VIDEO_RESOLUTION (LISTITEM_START + 47)
+#define LISTITEM_VIDEO_ASPECT (LISTITEM_START + 48)
+#define LISTITEM_AUDIO_CODEC (LISTITEM_START + 49)
+#define LISTITEM_AUDIO_CHANNELS (LISTITEM_START + 50)
+#define LISTITEM_AUDIO_LANGUAGE (LISTITEM_START + 51)
+#define LISTITEM_SUBTITLE_LANGUAGE (LISTITEM_START + 52)
#define LISTITEM_PROPERTY_START (LISTITEM_START + 200)
#define LISTITEM_PROPERTY_END (LISTITEM_PROPERTY_START + 1000)
@@ -615,6 +626,7 @@
TIME_FORMAT TranslateTimeFormat(const CStdString &format);
CStdString LocalizeTime(const CDateTime &time, TIME_FORMAT format) const;
bool GetItemBool(const CGUIListItem *item, int condition) const;
+ CStdString VideoWidthToResolutionDescription(int iWidth) const;
// Conditional string parameters for testing are stored in a vector for later retrieval.
// The offset into the string parameters array is returned.
Index: xbmc/utils/Makefile
===================================================================
--- xbmc/utils/Makefile (revision 20932)
+++ xbmc/utils/Makefile (working copy)
@@ -53,7 +53,8 @@
AsyncFileCopy.cpp \
DbusServer.cpp \
Atomics.cpp \
- LockFree.cpp
+ LockFree.cpp \
+ StreamDetails.cpp
LIB=utils.a
Index: xbmc/utils/StreamDetails.cpp
===================================================================
--- xbmc/utils/StreamDetails.cpp (revision 0)
+++ xbmc/utils/StreamDetails.cpp (revision 0)
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "stdafx.h"
+#include "StreamDetails.h"
+
+void CStreamDetail::Serialize(CArchive &ar)
+{
+ // there's nothing to do here, the type is stored externally and parent isn't stored
+}
+
+CStreamDetailVideo::CStreamDetailVideo() :
+ m_iWidth(0), m_iHeight(0), CStreamDetail(CStreamDetail::VIDEO)
+{
+}
+
+void CStreamDetailVideo::Serialize(CArchive& ar)
+{
+ CStreamDetail::Serialize(ar);
+ if (ar.IsStoring())
+ {
+ ar << m_strCodec;
+ ar << m_strAspect;
+ ar << m_iHeight;
+ ar << m_iWidth;
+ }
+ else
+ {
+ ar >>m_strCodec;
+ ar >> m_strAspect;
+ ar >> m_iHeight;
+ ar >> m_iWidth;
+ }
+}
+
+bool CStreamDetailVideo::IsWorseThan(CStreamDetail *that)
+{
+ if (that->m_eType != CStreamDetail::VIDEO)
+ return true;
+
+ // Best video stream is that with the most pixels
+ CStreamDetailVideo *sdv = (CStreamDetailVideo *)that;
+ return (sdv->m_iWidth * sdv->m_iHeight) > (m_iWidth * m_iHeight);
+}
+
+CStreamDetailAudio::CStreamDetailAudio() :
+ m_iChannels(-1), CStreamDetail(CStreamDetail::AUDIO)
+{
+}
+
+void CStreamDetailAudio::Serialize(CArchive& ar)
+{
+ CStreamDetail::Serialize(ar);
+ if (ar.IsStoring())
+ {
+ ar << m_strCodec;
+ ar << m_strLanguage;
+ ar << m_iChannels;
+ }
+ else
+ {
+ ar >> m_strCodec;
+ ar >> m_strLanguage;
+ ar >> m_iChannels;
+ }
+}
+
+int CStreamDetailAudio::GetCodecPriority() const
+{
+ if (m_strCodec == "eac3")
+ return 3;
+ if (m_strCodec == "dts")
+ return 2;
+ if (m_strCodec == "ac3")
+ return 1;
+ return 0;
+}
+
+bool CStreamDetailAudio::IsWorseThan(CStreamDetail *that)
+{
+ if (that->m_eType != CStreamDetail::AUDIO)
+ return true;
+
+ CStreamDetailAudio *sda = (CStreamDetailAudio *)that;
+ // First choice is the thing with the most channels
+ if (sda->m_iChannels > m_iChannels)
+ return true;
+
+ // In case of a tie, eac3 > dts > ac3 > all else.
+ return sda->GetCodecPriority() > GetCodecPriority();
+}
+
+CStreamDetailSubtitle::CStreamDetailSubtitle() :
+ CStreamDetail(CStreamDetail::SUBTITLE)
+{
+}
+
+void CStreamDetailSubtitle::Serialize(CArchive& ar)
+{
+ CStreamDetail::Serialize(ar);
+ if (ar.IsStoring())
+ {
+ ar << m_strLanguage;
+ }
+ else
+ {
+ ar >> m_strLanguage;
+ }
+}
+
+bool CStreamDetailSubtitle::IsWorseThan(CStreamDetail *that)
+{
+ if (that->m_eType != CStreamDetail::SUBTITLE)
+ return true;
+
+ // the preferred subtitle should be the one in the user's language
+ if (m_pParent)
+ if (m_pParent->m_strLanguage == m_strLanguage)
+ return false; // already the best
+ else
+ return (m_pParent->m_strLanguage == ((CStreamDetailSubtitle *)that)->m_strLanguage);
+ return false;
+}
+
+CStreamDetails& CStreamDetails::operator=(const CStreamDetails &that)
+{
+ if (this != &that)
+ {
+ Reset();
+ std::vector::const_iterator iter;
+ for (iter = that.m_vecItems.begin(); iter != that.m_vecItems.end(); iter++)
+ {
+ switch ((*iter)->m_eType)
+ {
+ case CStreamDetail::VIDEO:
+ AddStream(new CStreamDetailVideo((const CStreamDetailVideo &)(**iter)));
+ break;
+ case CStreamDetail::AUDIO:
+ AddStream(new CStreamDetailAudio((const CStreamDetailAudio &)(**iter)));
+ break;
+ case CStreamDetail::SUBTITLE:
+ AddStream(new CStreamDetailSubtitle((const CStreamDetailSubtitle &)(**iter)));
+ break;
+ }
+ }
+
+ DetermineBestStreams();
+ } /* if this != that */
+
+ return *this;
+}
+
+CStreamDetail *CStreamDetails::NewStream(CStreamDetail::StreamType type)
+{
+ CStreamDetail *retVal = NULL;
+ switch (type)
+ {
+ case CStreamDetail::VIDEO:
+ retVal = new CStreamDetailVideo();
+ break;
+ case CStreamDetail::AUDIO:
+ retVal = new CStreamDetailAudio();
+ break;
+ case CStreamDetail::SUBTITLE:
+ retVal = new CStreamDetailSubtitle();
+ break;
+ }
+
+ if (retVal)
+ AddStream(retVal);
+
+ return retVal;
+}
+
+const int CStreamDetails::GetStreamCount(CStreamDetail::StreamType type) const
+{
+ int retVal = 0;
+ std::vector::const_iterator iter;
+ for (iter = m_vecItems.begin(); iter != m_vecItems.end(); iter++)
+ if ((*iter)->m_eType == type)
+ retVal++;
+ return retVal;
+}
+
+const int CStreamDetails::GetVideoStreamCount(void) const
+{
+ return GetStreamCount(CStreamDetail::VIDEO);
+}
+
+const int CStreamDetails::GetAudioStreamCount(void) const
+{
+ return GetStreamCount(CStreamDetail::AUDIO);
+}
+
+const int CStreamDetails::GetSubtitleStreamCount(void) const
+{
+ return GetStreamCount(CStreamDetail::SUBTITLE);
+}
+
+CStreamDetails::CStreamDetails(const CStreamDetails &that)
+{
+ *this = that;
+}
+
+void CStreamDetails::AddStream(CStreamDetail *item)
+{
+ item->m_pParent = this;
+ m_vecItems.push_back(item);
+}
+
+void CStreamDetails::Reset(void)
+{
+ m_pBestVideo = NULL;
+ m_pBestAudio = NULL;
+ m_pBestSubtitle = NULL;
+
+ std::vector::iterator iter;
+ for (iter = m_vecItems.begin(); iter != m_vecItems.end(); iter++)
+ delete *iter;
+ m_vecItems.clear();
+}
+
+const CStreamDetail* CStreamDetails::GetNthStream(CStreamDetail::StreamType type, int idx) const
+{
+ if (idx == 0)
+ {
+ switch (type)
+ {
+ case CStreamDetail::VIDEO:
+ return m_pBestVideo;
+ break;
+ case CStreamDetail::AUDIO:
+ return m_pBestAudio;
+ break;
+ case CStreamDetail::SUBTITLE:
+ return m_pBestSubtitle;
+ break;
+ default:
+ return NULL;
+ break;
+ }
+ }
+
+ std::vector::const_iterator iter;
+ for (iter = m_vecItems.begin(); iter != m_vecItems.end(); iter++)
+ if ((*iter)->m_eType == type)
+ {
+ idx--;
+ if (idx < 1)
+ return *iter;
+ }
+
+ return NULL;
+}
+
+CStdString CStreamDetails::GetVideoCodec(int idx) const
+{
+ CStreamDetailVideo *item = (CStreamDetailVideo *)GetNthStream(CStreamDetail::VIDEO, idx);
+ if (item)
+ return item->m_strCodec;
+ else
+ return "";
+}
+
+CStdString CStreamDetails::GetVideoAspect(int idx) const
+{
+ CStreamDetailVideo *item = (CStreamDetailVideo *)GetNthStream(CStreamDetail::VIDEO, idx);
+ if (item)
+ return item->m_strAspect;
+ else
+ return "";
+}
+
+int CStreamDetails::GetVideoWidth(int idx) const
+{
+ CStreamDetailVideo *item = (CStreamDetailVideo *)GetNthStream(CStreamDetail::VIDEO, idx);
+ if (item)
+ return item->m_iWidth;
+ else
+ return 0;
+}
+
+int CStreamDetails::GetVideoHeight(int idx) const
+{
+ CStreamDetailVideo *item = (CStreamDetailVideo *)GetNthStream(CStreamDetail::VIDEO, idx);
+ if (item)
+ return item->m_iHeight;
+ else
+ return 0;
+}
+
+CStdString CStreamDetails::GetAudioCodec(int idx) const
+{
+ CStreamDetailAudio *item = (CStreamDetailAudio *)GetNthStream(CStreamDetail::AUDIO, idx);
+ if (item)
+ return item->m_strCodec;
+ else
+ return "";
+}
+
+CStdString CStreamDetails::GetAudioLanguage(int idx) const
+{
+ CStreamDetailAudio *item = (CStreamDetailAudio *)GetNthStream(CStreamDetail::AUDIO, idx);
+ if (item)
+ return item->m_strLanguage;
+ else
+ return "";
+}
+
+int CStreamDetails::GetAudioChannels(int idx) const
+{
+ CStreamDetailAudio *item = (CStreamDetailAudio *)GetNthStream(CStreamDetail::AUDIO, idx);
+ if (item)
+ return item->m_iChannels;
+ else
+ return -1;
+}
+
+CStdString CStreamDetails::GetSubtitleLanguage(int idx) const
+{
+ CStreamDetailSubtitle *item = (CStreamDetailSubtitle *)GetNthStream(CStreamDetail::SUBTITLE, idx);
+ if (item)
+ return item->m_strLanguage;
+ else
+ return "";
+}
+
+void CStreamDetails::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring())
+ {
+ ar << (int)m_vecItems.size();
+
+ std::vector::const_iterator iter;
+ for (iter = m_vecItems.begin(); iter != m_vecItems.end(); iter++)
+ {
+ // the type goes before the actual item. When loading we need
+ // to know the type before we can construct an instance to serialize
+ ar << (int)(*iter)->m_eType;
+ ar << (**iter);
+ }
+ }
+ else
+ {
+ int count;
+ ar >> count;
+
+ Reset();
+ for (int i=0; i> (int &)type;
+ p = NewStream(type);
+ if (p)
+ ar >> (*p);
+ }
+
+ DetermineBestStreams();
+ }
+}
+
+void CStreamDetails::DetermineBestStreams(void)
+{
+ m_pBestVideo = NULL;
+ m_pBestAudio = NULL;
+ m_pBestSubtitle = NULL;
+
+ std::vector::const_iterator iter;
+ for (iter = m_vecItems.begin(); iter != m_vecItems.end(); iter++)
+ {
+ CStreamDetail **champion;
+ switch ((*iter)->m_eType)
+ {
+ case CStreamDetail::VIDEO:
+ champion = (CStreamDetail **)&m_pBestVideo;
+ break;
+ case CStreamDetail::AUDIO:
+ champion = (CStreamDetail **)&m_pBestAudio;
+ break;
+ case CStreamDetail::SUBTITLE:
+ champion = (CStreamDetail **)&m_pBestSubtitle;
+ break;
+ default:
+ champion = NULL;
+ } /* switch type */
+
+ if (!champion)
+ continue;
+
+ if ((*champion == NULL) || (*champion)->IsWorseThan(*iter))
+ *champion = *iter;
+ } /* for each */
+}
Index: xbmc/utils/StreamDetails.h
===================================================================
--- xbmc/utils/StreamDetails.h (revision 0)
+++ xbmc/utils/StreamDetails.h (revision 0)
@@ -0,0 +1,132 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "Archive.h"
+#include
+
+class CStreamDetails;
+
+class CStreamDetail : public ISerializable
+{
+public:
+ enum StreamType {
+ VIDEO,
+ AUDIO,
+ SUBTITLE
+ };
+
+ CStreamDetail(StreamType type) : m_eType(type) {};
+ virtual void Serialize(CArchive& ar);
+ virtual bool IsWorseThan(CStreamDetail *that) { return true; };
+
+ const StreamType m_eType;
+
+protected:
+ CStreamDetails *m_pParent;
+ friend class CStreamDetails;
+};
+
+class CStreamDetailVideo : public CStreamDetail
+{
+public:
+ CStreamDetailVideo();
+ virtual void Serialize(CArchive& ar);
+ virtual bool IsWorseThan(CStreamDetail *that);
+
+ int m_iWidth;
+ int m_iHeight;
+ CStdString m_strAspect;
+ CStdString m_strCodec;
+};
+
+class CStreamDetailAudio : public CStreamDetail
+{
+public:
+ CStreamDetailAudio();
+ virtual void Serialize(CArchive& ar);
+ virtual bool IsWorseThan(CStreamDetail *that);
+
+ int m_iChannels;
+ CStdString m_strCodec;
+ CStdString m_strLanguage;
+private:
+ int GetCodecPriority() const;
+};
+
+class CStreamDetailSubtitle : public CStreamDetail
+{
+public:
+ CStreamDetailSubtitle();
+ virtual void Serialize(CArchive& ar);
+ virtual bool IsWorseThan(CStreamDetail *that);
+
+ CStdString m_strLanguage;
+};
+
+class CStreamDetails : public ISerializable
+{
+public:
+ CStreamDetails() { Reset(); };
+ CStreamDetails(const CStreamDetails &that);
+ ~CStreamDetails() { Reset(); };
+ CStreamDetails& operator=(const CStreamDetails &that);
+
+ const bool HasItems(void) const { return m_vecItems.size() > 0; };
+ const int GetStreamCount(CStreamDetail::StreamType type) const;
+ const int GetVideoStreamCount(void) const;
+ const int GetAudioStreamCount(void) const;
+ const int GetSubtitleStreamCount(void) const;
+ const CStreamDetail* GetNthStream(CStreamDetail::StreamType type, int idx) const;
+
+ CStdString GetVideoCodec(int idx = 0) const;
+ CStdString GetVideoAspect(int idx = 0) const;
+ int GetVideoWidth(int idx = 0) const;
+ int GetVideoHeight(int idx = 0) const;
+
+ CStdString GetAudioCodec(int idx = 0) const;
+ CStdString GetAudioLanguage(int idx = 0) const;
+ int GetAudioChannels(int idx = 0) const;
+
+ CStdString GetSubtitleLanguage(int idx = 0) const;
+
+ void AddStream(CStreamDetail *item);
+ void Reset(void);
+ void DetermineBestStreams(void);
+
+ virtual void Serialize(CArchive& ar);
+
+ // Language to use for "best" subtitle stream
+ CStdString m_strLanguage;
+
+private:
+ CStreamDetail *NewStream(CStreamDetail::StreamType type);
+ std::vector m_vecItems;
+ CStreamDetailVideo *m_pBestVideo;
+ CStreamDetailAudio *m_pBestAudio;
+ CStreamDetailSubtitle *m_pBestSubtitle;
+};
+
+class IStreamDetailsObserver
+{
+public:
+ virtual void OnStreamDetails(const CStreamDetails &details, const CStdString &strFileName, long lFileId) = 0;
+};
Index: xbmc/VideoDatabase.cpp
===================================================================
--- xbmc/VideoDatabase.cpp (revision 20932)
+++ xbmc/VideoDatabase.cpp (working copy)
@@ -44,7 +44,7 @@
using namespace DIRECTORY;
using namespace VIDEO;
-#define VIDEO_DATABASE_VERSION 26
+#define VIDEO_DATABASE_VERSION 27
#define VIDEO_DATABASE_OLD_VERSION 3.f
#define VIDEO_DATABASE_NAME "MyVideos34.db"
#define RECENTLY_ADDED_LIMIT 25
@@ -271,6 +271,12 @@
m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_1 ON directorlinkmusicvideo ( idDirector, idMVideo )\n");
m_pDS->exec("CREATE UNIQUE INDEX ix_directorlinkmusicvideo_2 ON directorlinkmusicvideo ( idMVideo, idDirector )\n");
+ CLog::Log(LOGINFO, "create streaminfo table");
+ m_pDS->exec("CREATE TABLE streamdetails (idFile integer, iStreamType integer, "
+ "strVideoCodec text, strVideoAspect text, iVideoWidth integer, iVideoHeight integer, "
+ "strAudioCodec text, iAudioChannels integer, strAudioLanguage text, strSubtitleLanguage text)");
+ m_pDS->exec("CREATE INDEX ix_streamdetails ON streamdetails (idFile)");
+
CLog::Log(LOGINFO, "create tvshowview");
CStdString showview=FormatSQL("create view tvshowview as select tvshow.*,path.strPath as strPath,"
"counts.totalcount as totalCount,counts.watchedcount as watchedCount,"
@@ -1737,6 +1743,9 @@
AddActorToMovie(lMovieId, lActor, it->strRole);
}
+ if (details.HasStreamDetails())
+ SetStreamDetailsForFileId(details.m_streamDetails, lFileId);
+
// update our movie table (we know it was added already above)
// and insert the new row
CStdString sql = "update movie set " + GetValueString(info, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets);
@@ -1814,7 +1823,6 @@
try
{
BeginTransaction();
-
if (lEpisodeId == -1)
{
lEpisodeId = GetEpisodeId(strFilenameAndPath);
@@ -1860,6 +1868,12 @@
AddDirectorToEpisode(lEpisodeId, vecDirectors[i]);
}
+ if (details.HasStreamDetails())
+ if (details.m_iFileId != -1)
+ SetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
+ else
+ SetStreamDetailsForFile(details.m_streamDetails, strFilenameAndPath);
+
// and insert the new row
CStdString sql = "update episode set " + GetValueString(details, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets);
sql += FormatSQL("where idEpisode=%u", lEpisodeId);
@@ -1930,6 +1944,9 @@
AddStudioToMusicVideo(lMVideoId, vecStudios[i]);
}
+ if (details.HasStreamDetails())
+ SetStreamDetailsForFileId(details.m_streamDetails, lFileId);
+
// update our movie table (we know it was added already above)
// and insert the new row
CStdString sql = "update musicvideo set " + GetValueString(details, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets);
@@ -1943,6 +1960,61 @@
}
}
+void CVideoDatabase::SetStreamDetailsForFile(const CStreamDetails& details, const CStdString &strFileNameAndPath)
+{
+ // AddFile checks to make sure the file isn't already in the DB first
+ long lFileId = AddFile(strFileNameAndPath);
+ if (lFileId < 0)
+ return;
+ SetStreamDetailsForFileId(details, lFileId);
+}
+
+void CVideoDatabase::SetStreamDetailsForFileId(const CStreamDetails& details, long lFileId)
+{
+ if (lFileId < 0)
+ return;
+
+ try
+ {
+ BeginTransaction();
+ m_pDS->exec(FormatSQL("DELETE FROM streamdetails WHERE idFile = %u", lFileId));
+
+ for (int i=0; iexec(FormatSQL("INSERT INTO streamdetails "
+ "(idFile, iStreamType, strVideoCodec, strVideoAspect, iVideoWidth, iVideoHeight) "
+ "VALUES (%u,%i,'%s','%s',%i,%i)",
+ lFileId, (int)CStreamDetail::VIDEO,
+ details.GetVideoCodec(i).c_str(), details.GetVideoAspect().c_str(),
+ details.GetVideoWidth(i), details.GetVideoHeight(i)));
+ }
+ for (int i=0; iexec(FormatSQL("INSERT INTO streamdetails "
+ "(idFile, iStreamType, strAudioCodec, iAudioChannels, strAudioLanguage) "
+ "VALUES (%u,%i,'%s',%i,'%s')",
+ lFileId, (int)CStreamDetail::AUDIO,
+ details.GetAudioCodec(i).c_str(), details.GetAudioChannels(i),
+ details.GetAudioLanguage(i).c_str()));
+ }
+ for (int i=0; iexec(FormatSQL("INSERT INTO streamdetails "
+ "(idFile, iStreamType, strSubtitleLanguage) "
+ "VALUES (%u,%i,'%s')",
+ lFileId, (int)CStreamDetail::SUBTITLE,
+ details.GetSubtitleLanguage(i).c_str()));
+ }
+
+ CommitTransaction();
+ }
+ catch (...)
+ {
+ RollbackTransaction();
+ CLog::Log(LOGERROR, "%s (%u) failed", __FUNCTION__, lFileId);
+ }
+}
+
//********************************************************************************************************************************
void CVideoDatabase::GetFilePathById(long lMovieId, CStdString &filePath, VIDEODB_CONTENT_TYPE iType)
{
@@ -2267,6 +2339,10 @@
return ;
}
+ long lFileId = GetFileId(strFilenameAndPath);
+ if (lFileId < 0)
+ return ;
+
BeginTransaction();
CStdString strSQL;
@@ -2285,6 +2361,8 @@
if (!bKeepThumb)
DeleteThumbForItem(strFilenameAndPath,false);
+ DeleteStreamDetails(lFileId);
+
// keep the movie table entry, linking to tv shows, and bookmarks
// so we can update the data in place
// the ancilliary tables are still purged
@@ -2426,6 +2504,8 @@
if (!bKeepThumb)
DeleteThumbForItem(strFilenameAndPath,false);
+ DeleteStreamDetails(lFileId);
+
// keep episode table entry and bookmarks so we can update the data in place
// the ancilliary tables are still purged
if (!bKeepId)
@@ -2464,6 +2544,10 @@
return ;
}
+ long lFileId = GetFileId(strFilenameAndPath);
+ if (lFileId < 0)
+ return ;
+
BeginTransaction();
CStdString strSQL;
@@ -2482,6 +2566,8 @@
if (!bKeepThumb)
DeleteThumbForItem(strFilenameAndPath,false);
+ DeleteStreamDetails(lFileId);
+
// keep the music video table entry and bookmarks so we can update data in place
// the ancilliary tables are still purged
if (!bKeepId)
@@ -2512,6 +2598,11 @@
}
}
+void CVideoDatabase::DeleteStreamDetails(long lFileId)
+{
+ m_pDS->exec(FormatSQL("delete from streamdetails where idFile=%u", lFileId));
+}
+
void CVideoDatabase::GetDetailsFromDB(auto_ptr &pDS, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details)
{
for (int i = min + 1; i < max; i++)
@@ -2561,6 +2652,66 @@
return details;
}
+bool CVideoDatabase::GetStreamDetailsForFileId(CStreamDetails& details, long lFileId) const
+{
+ if (lFileId < 0)
+ return false;
+
+ bool retVal = false;
+
+ dbiplus::Dataset *pDS = m_pDB->CreateDataset();
+ CStdString strSQL = FormatSQL("SELECT * FROM streamdetails WHERE idFile = %u", lFileId);
+ pDS->query(strSQL);
+
+ details.Reset();
+ while (!pDS->eof())
+ {
+ CStreamDetail::StreamType e = (CStreamDetail::StreamType)pDS->fv(1).get_asInteger();
+ switch (e)
+ {
+ case CStreamDetail::VIDEO:
+ {
+ CStreamDetailVideo *p = new CStreamDetailVideo();
+ p->m_strCodec = pDS->fv(2).get_asString();
+ p->m_strAspect = pDS->fv(3).get_asString();
+ p->m_iWidth = pDS->fv(4).get_asInteger();
+ p->m_iHeight = pDS->fv(5).get_asInteger();
+ details.AddStream(p);
+ retVal = true;
+ break;
+ }
+ case CStreamDetail::AUDIO:
+ {
+ CStreamDetailAudio *p = new CStreamDetailAudio();
+ p->m_strCodec = pDS->fv(6).get_asString();
+ if (pDS->fv(7).get_isNull())
+ p->m_iChannels = -1;
+ else
+ p->m_iChannels = pDS->fv(7).get_asInteger();
+ p->m_strLanguage = pDS->fv(8).get_asString();
+ details.AddStream(p);
+ retVal = true;
+ break;
+ }
+ case CStreamDetail::SUBTITLE:
+ {
+ CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
+ p->m_strLanguage = pDS->fv(9).get_asString();
+ details.AddStream(p);
+ retVal = true;
+ break;
+ }
+ }
+
+ pDS->next();
+ }
+
+ pDS->close();
+ details.DetermineBestStreams();
+
+ return retVal;
+}
+
CVideoInfoTag CVideoDatabase::GetDetailsForMovie(auto_ptr &pDS, bool needsCast /* = false */)
{
CVideoInfoTag details;
@@ -2572,10 +2723,11 @@
GetDetailsFromDB(pDS, VIDEODB_ID_MIN, VIDEODB_ID_MAX, DbMovieOffsets, details);
details.m_iDbId = lMovieId;
-
GetCommonDetails(pDS, details);
movieTime += timeGetTime() - time; time = timeGetTime();
+ GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
+
if (needsCast)
{
// create cast string
@@ -2644,12 +2796,13 @@
GetDetailsFromDB(pDS, VIDEODB_ID_EPISODE_MIN, VIDEODB_ID_EPISODE_MAX, DbEpisodeOffsets, details);
details.m_iDbId = lEpisodeId;
-
GetCommonDetails(pDS, details);
movieTime += timeGetTime() - time; time = timeGetTime();
details.m_strShowTitle = pDS->fv(VIDEODB_DETAILS_EPISODE_TVSHOW_NAME).get_asString();
+ GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
+
if (needsCast)
{
// create cast string
@@ -2695,16 +2848,18 @@
GetDetailsFromDB(pDS, VIDEODB_ID_MUSICVIDEO_MIN, VIDEODB_ID_MUSICVIDEO_MAX, DbMusicVideoOffsets, details);
details.m_iDbId = lMovieId;
-
GetCommonDetails(pDS, details);
movieTime += timeGetTime() - time; time = timeGetTime();
+ GetStreamDetailsForFileId(details.m_streamDetails, details.m_iFileId);
+
details.m_strPictureURL.Parse();
return details;
}
void CVideoDatabase::GetCommonDetails(auto_ptr &pDS, CVideoInfoTag &details)
{
+ details.m_iFileId = pDS->fv(VIDEODB_DETAILS_FILEID).get_asLong();
details.m_strPath = pDS->fv(VIDEODB_DETAILS_PATH).get_asString();
CStdString strFileName = pDS->fv(VIDEODB_DETAILS_FILE).get_asString();
ConstructPath(details.m_strFileNameAndPath,details.m_strPath,strFileName);
@@ -3397,6 +3552,14 @@
m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_1 ON studiolinktvshow ( idStudio, idShow)\n");
m_pDS->exec("CREATE UNIQUE INDEX ix_studiolinktvshow_2 ON studiolinktvshow ( idShow, idStudio)\n");
}
+ if (iVersion < 27)
+ {
+ // Add the streamdetail table
+ m_pDS->exec("CREATE TABLE streamdetails (idFile integer, iStreamType integer, "
+ "strVideoCodec text, strVideoAspect text, iVideoWidth integer, iVideoHeight integer, "
+ "strAudioCodec text, iAudioChannels integer, strAudioLanguage text, strSubtitleLanguage text)");
+ m_pDS->exec("CREATE INDEX ix_streamdetails ON streamdetails (idFile)");
+ }
}
catch (...)
{
@@ -3859,7 +4022,8 @@
pItem->SetLabelPreformated(true);
if (!items.Contains(pItem->m_strPath))
{
- CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),it->second.second);
+ pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
+ CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),pItem->GetVideoInfoTag()->m_strArtist);
if (CFile::Exists(strThumb))
pItem->SetThumbnailImage(strThumb);
items.Add(pItem);
@@ -3878,8 +4042,7 @@
pItem->SetLabelPreformated(true);
if (!items.Contains(pItem->m_strPath))
{
- pItem->GetVideoInfoTag()->m_strArtist = m_pDS->fv(2).get_asString();
- CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),pItem->GetVideoInfoTag()->m_strArtist);
+ CStdString strThumb = CUtil::GetCachedAlbumThumb(pItem->GetLabel(),m_pDS->fv(2).get_asString());
if (CFile::Exists(strThumb))
pItem->SetThumbnailImage(strThumb);
items.Add(pItem);
@@ -4452,24 +4615,39 @@
// get data from returned rows
items.Reserve(iRowsFound);
+ DWORD times[6];
+ memset(times, 0, sizeof(times));
while (!m_pDS->eof())
{
- long lMovieId = m_pDS->fv("idMovie").get_asLong();
+ LARGE_INTEGER t1,t2;
+ QueryPerformanceCounter(&t1);
CVideoInfoTag movie = GetDetailsForMovie(m_pDS);
+ QueryPerformanceCounter(&t2); times[0] += t2.QuadPart - t1.QuadPart;
if (g_settings.m_vecProfiles[0].getLockMode() == LOCK_MODE_EVERYONE ||
g_passwordManager.bMasterUser ||
g_passwordManager.IsDatabasePathUnlocked(movie.m_strPath, g_settings.m_videoSources))
{
+ QueryPerformanceCounter(&t1);
CFileItemPtr pItem(new CFileItem(movie));
- pItem->m_strPath.Format("%s%ld", strBaseDir.c_str(), lMovieId);
+ QueryPerformanceCounter(&t2); times[1] += t2.QuadPart - t1.QuadPart;
+ QueryPerformanceCounter(&t1);
+ pItem->m_strPath.Format("%s%ld", strBaseDir.c_str(), movie.m_iDbId);
+ QueryPerformanceCounter(&t2); times[2] += t2.QuadPart - t1.QuadPart;
+ QueryPerformanceCounter(&t1);
pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_playCount > 0);
+ QueryPerformanceCounter(&t2); times[3] += t2.QuadPart - t1.QuadPart;
+ QueryPerformanceCounter(&t1);
items.Add(pItem);
+ QueryPerformanceCounter(&t2); times[4] += t2.QuadPart - t1.QuadPart;
}
+ QueryPerformanceCounter(&t1);
m_pDS->next();
+ QueryPerformanceCounter(&t2); times[5] += t2.QuadPart - t1.QuadPart;
}
- CLog::Log(LOGDEBUG,"Time to retrieve movies from dataset = %d",
- timeGetTime() - time);
+ CLog::Log(LOGDEBUG,"Time to retrieve %i movies from dataset = %d|%u,%u,%u,%u,%u,%u",
+ iRowsFound, timeGetTime() - time,
+ times[0],times[1],times[2],times[3],times[4],times[5]);
// cleanup
m_pDS->close();
@@ -6183,6 +6361,10 @@
sql = "delete from files where idFile in " + filesToDelete;
m_pDS->exec(sql.c_str());
+ CLog::Log(LOGDEBUG, "%s Cleaning streamdetails table", __FUNCTION__);
+ sql = "delete from streamdetails where idFile in " + filesToDelete;
+ m_pDS->exec(sql.c_str());
+
CLog::Log(LOGDEBUG, "%s Cleaning bookmark table", __FUNCTION__);
sql = "delete from bookmark where idFile in " + filesToDelete;
m_pDS->exec(sql.c_str());
Index: xbmc/VideoDatabase.h
===================================================================
--- xbmc/VideoDatabase.h (revision 20932)
+++ xbmc/VideoDatabase.h (working copy)
@@ -57,7 +57,8 @@
// these defines are based on how many columns we have and which column certain data is going to be in
// when we do GetDetailsForMovie()
-#define VIDEODB_MAX_COLUMNS 21 // leave room for the fileid
+#define VIDEODB_MAX_COLUMNS 21
+#define VIDEODB_DETAILS_FILEID VIDEODB_MAX_COLUMNS + 1
#define VIDEODB_DETAILS_FILE VIDEODB_MAX_COLUMNS + 2
#define VIDEODB_DETAILS_PATH VIDEODB_MAX_COLUMNS + 3
#define VIDEODB_DETAILS_PLAYCOUNT VIDEODB_MAX_COLUMNS + 4
@@ -331,6 +332,7 @@
void GetTvShowInfo(const CStdString& strPath, CVideoInfoTag& details, long lTvShowId = -1);
bool GetEpisodeInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, long lEpisodeId = -1);
void GetMusicVideoInfo(const CStdString& strFilenameAndPath, CVideoInfoTag& details, long idMVideo=-1);
+ bool GetStreamDetailsForFileId(CStreamDetails& details, long lFileId) const;
long GetPathId(const CStdString& strPath);
long GetTvShowId(const CStdString& strPath);
@@ -342,6 +344,8 @@
long SetDetailsForTvShow(const CStdString& strPath, const CVideoInfoTag& details);
long SetDetailsForEpisode(const CStdString& strFilenameAndPath, const CVideoInfoTag& details, long idShow, long lEpisodeId=-1);
void SetDetailsForMusicVideo(const CStdString& strFilenameAndPath, const CVideoInfoTag& details);
+ void SetStreamDetailsForFile(const CStreamDetails& details, const CStdString &strFileNameAndPath);
+ void SetStreamDetailsForFileId(const CStreamDetails& details, long lFileId);
void DeleteMovie(const CStdString& strFilenameAndPath, bool bKeepId = false, bool bKeepThumb = false);
void DeleteTvShow(const CStdString& strPath, bool bKeepId = false, bool bKeepThumb = false);
@@ -504,6 +508,7 @@
void AddGenreAndDirectorsAndStudios(const CVideoInfoTag& details, std::vector& vecDirectors, std::vector& vecGenres, std::vector& vecStudios);
int GetPlayCount(long id);
+ void DeleteStreamDetails(long lFileId);
CVideoInfoTag GetDetailsByTypeAndId(VIDEODB_CONTENT_TYPE type, long id);
CVideoInfoTag GetDetailsForMovie(std::auto_ptr &pDS, bool needsCast = false);
CVideoInfoTag GetDetailsForTvShow(std::auto_ptr &pDS, bool needsCast = false);
Index: xbmc/VideoInfoTag.cpp
===================================================================
--- xbmc/VideoInfoTag.cpp (revision 20932)
+++ xbmc/VideoInfoTag.cpp (working copy)
@@ -65,11 +65,13 @@
m_iSpecialSortEpisode = -1;
m_fRating = 0.0f;
m_iDbId = -1;
+ m_iFileId = -1;
m_iBookmarkId = -1;
m_iTrack = -1;
m_fanart.m_xml = "";
m_strRuntime = "";
m_lastPlayed = "";
+ m_streamDetails.Reset();
m_playCount = 0;
}
@@ -136,6 +138,38 @@
XMLUtils::SetString(movie, "studio", m_strStudio);
XMLUtils::SetString(movie, "trailer", m_strTrailer);
+ if (m_streamDetails.HasItems())
+ {
+ // it goes fileinfo/streamdetails/[video|audio|subtitle]
+ TiXmlElement fileinfo("fileinfo");
+ TiXmlElement streamdetails("streamdetails");
+ for (int iStream=0; iStreamInsertEndChild(fileinfo);
+ } /* if has stream details */
+
// cast
for (iCast it = m_cast.begin(); it != m_cast.end(); ++it)
{
@@ -223,10 +257,12 @@
ar << m_iEpisode;
ar << m_fRating;
ar << m_iDbId;
+ ar << m_iFileId;
ar << m_iSpecialSortSeason;
ar << m_iSpecialSortEpisode;
ar << m_iBookmarkId;
ar << m_iTrack;
+ ar << m_streamDetails;
}
else
{
@@ -280,10 +316,12 @@
ar >> m_iEpisode;
ar >> m_fRating;
ar >> m_iDbId;
+ ar >> m_iFileId;
ar >> m_iSpecialSortSeason;
ar >> m_iSpecialSortEpisode;
ar >> m_iBookmarkId;
ar >> m_iTrack;
+ ar >> m_streamDetails;
}
}
@@ -467,6 +505,48 @@
node = node->NextSibling("artist");
}
+ m_streamDetails.Reset();
+ node = movie->FirstChildElement("fileinfo");
+ if (node)
+ {
+ // Try to pull from fileinfo/streamdetails/[video|audio|subtitle]
+ const TiXmlNode *nodeStreamDetails = node->FirstChild("streamdetails");
+ if (nodeStreamDetails)
+ {
+ const TiXmlNode *nodeDetail = NULL;
+ while (nodeDetail = nodeStreamDetails->IterateChildren("audio", nodeDetail))
+ {
+ CStreamDetailAudio *p = new CStreamDetailAudio();
+ XMLUtils::GetString(nodeDetail, "codec", p->m_strCodec);
+ XMLUtils::GetString(nodeDetail, "language", p->m_strLanguage);
+ XMLUtils::GetInt(nodeDetail, "channels", p->m_iChannels);
+ p->m_strCodec = p->m_strCodec.ToLower();
+ p->m_strLanguage = p->m_strLanguage.ToLower();
+ m_streamDetails.AddStream(p);
+ }
+ nodeDetail = NULL;
+ while (nodeDetail = nodeStreamDetails->IterateChildren("video", nodeDetail))
+ {
+ CStreamDetailVideo *p = new CStreamDetailVideo();
+ XMLUtils::GetString(nodeDetail, "codec", p->m_strCodec);
+ XMLUtils::GetString(nodeDetail, "aspect", p->m_strAspect);
+ XMLUtils::GetInt(nodeDetail, "width", p->m_iWidth);
+ XMLUtils::GetInt(nodeDetail, "height", p->m_iHeight);
+ p->m_strCodec = p->m_strCodec.ToLower();
+ m_streamDetails.AddStream(p);
+ }
+ nodeDetail = NULL;
+ while (nodeDetail = nodeStreamDetails->IterateChildren("subtitle", nodeDetail))
+ {
+ CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
+ XMLUtils::GetString(nodeDetail, "language", p->m_strLanguage);
+ p->m_strLanguage = p->m_strLanguage.ToLower();
+ m_streamDetails.AddStream(p);
+ }
+ }
+ m_streamDetails.DetermineBestStreams();
+ } /* if fileinfo */
+
const TiXmlElement *epguide = movie->FirstChildElement("episodeguide");
if (epguide)
{
@@ -586,3 +666,7 @@
}
+bool CVideoInfoTag::HasStreamDetails() const
+{
+ return m_streamDetails.HasItems();
+}
Index: xbmc/VideoInfoTag.h
===================================================================
--- xbmc/VideoInfoTag.h (revision 20932)
+++ xbmc/VideoInfoTag.h (working copy)
@@ -25,6 +25,7 @@
#include "utils/Archive.h"
#include "utils/ScraperUrl.h"
#include "utils/Fanart.h"
+#include "utils/StreamDetails.h"
#include
@@ -44,6 +45,7 @@
bool Save(TiXmlNode *node, const CStdString &tag, bool savePathInfo = true);
virtual void Serialize(CArchive& ar);
const CStdString GetCast(bool bIncludeRole = false) const;
+ bool HasStreamDetails() const;
CStdString m_strDirector;
CStdString m_strWritingCredits;
@@ -80,13 +82,16 @@
int m_iYear;
int m_iSeason;
int m_iEpisode;
- int m_iDbId;
+ int m_iDbId;
+ long m_iFileId;
int m_iSpecialSortSeason;
int m_iSpecialSortEpisode;
int m_iTrack;
float m_fRating;
int m_iBookmarkId;
CFanart m_fanart;
+ CStreamDetails m_streamDetails;
+
private:
void ParseNative(const TiXmlElement* movie);
void ParseMyMovies(const TiXmlElement* movie);